我目前正在开发一个可以接受来自多台客户端计算机的多个连接的 C# Socket 服务器。服务器的目标是允许客户端“订阅”和“取消订阅”服务器事件。
到目前为止,我已经在这里愉快地看了一下:http: //msdn.microsoft.com/en-us/library/5w7b7x5f (v=VS.100).aspx和http://msdn.microsoft.com/ en-us/library/fx6588te.aspx的想法。
我发送的所有消息都是加密的,因此我将我希望发送的字符串消息转换为 byte[] 数组,然后在将消息长度预先附加到数据并通过连接发送出去之前加密数据.
让我印象深刻的一个问题是:在接收端,当只收到一半的消息时,Socket.EndReceive()(或相关的回调)似乎有可能返回。有没有一种简单的方法来确保每条消息都被“完整”接收并且一次只接收一条消息?
编辑:例如,我认为 .NET / Windows 套接字不会“包装”消息以确保在一次 Socket.Receive() 调用中接收到使用 Socket.Send() 发送的单个消息?或者是吗?
到目前为止我的实现:
private void StartListening()
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0], Constants.PortNumber);
Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEP);
listener.Listen(10);
while (true)
{
// Reset the event.
this.listenAllDone.Reset();
// Begin waiting for a connection
listener.BeginAccept(new AsyncCallback(this.AcceptCallback), listener);
// Wait for the event.
this.listenAllDone.WaitOne();
}
}
private void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Signal the main thread to continue.
this.listenAllDone.Set();
// Accept the incoming connection and save a reference to the new Socket in the client data.
CClient client = new CClient();
client.Socket = handler;
lock (this.clientList)
{
this.clientList.Add(client);
}
while (true)
{
this.readAllDone.Reset();
// Begin waiting on data from the client.
handler.BeginReceive(client.DataBuffer, 0, client.DataBuffer.Length, 0, new AsyncCallback(this.ReadCallback), client);
this.readAllDone.WaitOne();
}
}
private void ReadCallback(IAsyncResult asyn)
{
CClient theClient = (CClient)asyn.AsyncState;
// End the receive and get the number of bytes read.
int iRx = theClient.Socket.EndReceive(asyn);
if (iRx != 0)
{
// Data was read from the socket.
// So save the data
byte[] recievedMsg = new byte[iRx];
Array.Copy(theClient.DataBuffer, recievedMsg, iRx);
this.readAllDone.Set();
// Decode the message recieved and act accordingly.
theClient.DecodeAndProcessMessage(recievedMsg);
// Go back to waiting for data.
this.WaitForData(theClient);
}
}