I am now writing a tiny framework based on SocketAsyncEventArgs , this class is created based on IOCP , which is much more efficient than APM mode.
but here, I got some problems when running test.
here is the server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Windows.Forms;
namespace SocketServer
{
public class Server
{
Socket serverSocket;
SocketAsyncEventArgs socketAsyncEventArgs;
SocketAsyncEventArgsPool readWritePool;
HandleMessage handleMessage;
BufferManager buffeManager;
const int PrefixSize = 11;
public void Init(int port,int connections,int receiveBufferSize)
{
buffeManager = new BufferManager(receiveBufferSize * connections * 2, receiveBufferSize);
buffeManager.InitBuffer();
readWritePool = new SocketAsyncEventArgsPool(connections);
SocketAsyncEventArgs socketAsyncEventArgsPooling;
for (int i = 0; i < connections; i++)
{
socketAsyncEventArgsPooling = new SocketAsyncEventArgs();
socketAsyncEventArgsPooling.Completed += readEventArgsIO_Completed;
buffeManager.SetBuffer(socketAsyncEventArgsPooling);
readWritePool.Push(socketAsyncEventArgsPooling);
}
handleMessage = new HandleMessage();
IPAddress[] addressList = Dns.GetHostEntry(Environment.MachineName).AddressList;
IPEndPoint localEndPoint = new IPEndPoint(addressList[addressList.Length - 1], port);
this.serverSocket = new Socket(localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
if (localEndPoint.AddressFamily == AddressFamily.InterNetworkV6)
{
this.serverSocket.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)27, false);
this.serverSocket.Bind(new IPEndPoint(IPAddress.IPv6Any, localEndPoint.Port));
}
else
{
this.serverSocket.Bind(localEndPoint);
}
this.serverSocket.Listen(100);
StartAccept(null);
}
private void StartAccept(SocketAsyncEventArgs acceptSocketAsyncEventArgs)
{
if (acceptSocketAsyncEventArgs == null)
{
acceptSocketAsyncEventArgs = new SocketAsyncEventArgs();
acceptSocketAsyncEventArgs.Completed += socketAsyncEventArgs_Completed;
}
else
{
acceptSocketAsyncEventArgs.AcceptSocket = null;
}
Boolean willRaiseEvent = this.serverSocket.AcceptAsync(acceptSocketAsyncEventArgs);
if (!willRaiseEvent)
{
this.ProcessAccept(acceptSocketAsyncEventArgs);
}
}
private void socketAsyncEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
ProcessAccept(e);
}
private void readEventArgsIO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
this.ProcessReceive(e);
break;
case SocketAsyncOperation.Send:
//this.ProcessSend(e);
break;
default:
throw new ArgumentException("The last operation completed on the socket was not a receive or send");
}
}
private void ProcessAccept(SocketAsyncEventArgs e)
{
SocketAsyncEventArgs readEventArgs = this.readWritePool.Pop();
//SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
readEventArgs.UserToken = e.AcceptSocket;
Console.WriteLine("---------------------------------------------------");
Console.WriteLine("Client Connected {0}",e.AcceptSocket.RemoteEndPoint);
Boolean willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
if (!willRaiseEvent)
{
this.ProcessReceive(readEventArgs);
}
this.StartAccept(e);
}
private void ProcessReceive(SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0)
{
if (e.SocketError == SocketError.Success)
{
Console.WriteLine("receiving data, {0} bytes", e.BytesTransferred);
Socket socket = e.UserToken as Socket;
int bytesTransferred = e.BytesTransferred;
string received = Encoding.ASCII.GetString(e.Buffer, e.Offset, bytesTransferred);
Console.WriteLine("Received:{0}", received);
string[] msgArray = handleMessage.GetActualString(received);
foreach (var msg in msgArray)
{
Console.WriteLine("After Split:{0}", msg);
}
// Array.Clear(e.Buffer, e.Offset, bytesTransferred);
Boolean willRaiseEvent = socket.SendAsync(e);
if (!willRaiseEvent)
{
this.ProcessSend(e);
}
readWritePool.Push(e);
}
}
}
private void ProcessSend(SocketAsyncEventArgs e)
{
}
}
}
here is my client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
namespace SocketClient
{
class Program
{
static void Main(string[] args)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.129"), 1234);
SocketAsyncEventArgs connectArgs = new SocketAsyncEventArgs();
connectArgs.RemoteEndPoint = ipEndPoint;
connectArgs.Completed += OnConnected;
socket.ConnectAsync(connectArgs);
socket.SendBufferSize = Int16.MaxValue;
//NetworkStream streamToServer = new NetworkStream(socket);
string text = "[length=12]Hello server";
byte[] sendBuffer = Encoding.ASCII.GetBytes(text);
for (int i = 0; i < 5; i++)
{
SocketAsyncEventArgs sendArgs = new SocketAsyncEventArgs();
sendArgs.UserToken = socket;
sendArgs.SetBuffer(sendBuffer,0,sendBuffer.Length);
sendArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnSend);
socket.SendAsync(sendArgs);
}
Console.ReadLine();
}
private static void OnSend(object sender, SocketAsyncEventArgs e)
{
Console.WriteLine("SendOk: {0}", e.UserToken.ToString());
}
private static void OnConnected(object sender, SocketAsyncEventArgs e)
{
Console.WriteLine("Conectioned");
}
}
}
But when I start several clients, i found that sometimes the server can receive the messages correctly; but sometimes, the server can only receive the first message, the remain messages seems are all "lost", anyone can advice? thx.
I heard from someone that, I should realize my own protocol to transfer data, but anyone can tell me how to define? thx
below is the capture of the screen shoot of server side: