我现在正在写一个基于 SocketAsyncEventArgs 的小框架,这个类是基于 IOCP 创建的,比 APM 模式效率高得多。但是在这里,我在运行测试时遇到了一些问题。这是服务器代码:
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)
{
}
}
}
这是我的客户代码:
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");
}
}
}
但是当我启动几个客户端时,我发现有时服务器可以正确接收消息;但有时,服务器只能收到第一条消息,剩下的消息似乎都“丢失”了,任何人都可以建议吗?谢谢。
听人说,我应该实现自己的数据传输协议,但是谁能告诉我怎么定义?谢谢
下面是服务器端的截图: