引言
项目中用到了Socket,这里做个控制台小示例记录一下。
Client
客户端的Receive用了异步方法,保持长连接,可以随时发送消息和响应服务端的消息,如下
static string ClientReceiveMessage = ""; static byte[] receivedBytes = new byte[1024]; static void Main(string[] args) { IPHostEntry ipHost = Dns.Resolve("127.0.0.1"); IPAddress ipAddress = ipHost.AddressList[0]; IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 2012); string sendingMessage = "Hello World Socket Test"; Console.WriteLine("Creating message: Hello World Socket Test"); Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); sender.Connect(ipEndPoint); sender.BeginReceive(receivedBytes, 0, receivedBytes.Length, 0, ReceiveCallback, sender); while (true) { sendingMessage = Console.ReadLine(); byte[] forwardMessage = Encoding.ASCII.GetBytes(sendingMessage + "[FINAL]"); sender.Send(forwardMessage); } } private static void ReceiveCallback(IAsyncResult ar) { Socket client = (Socket)ar.AsyncState; int totalBytesReceived = client.EndReceive(ar); if (totalBytesReceived > 0) { ClientReceiveMessage += Encoding.ASCII.GetString(receivedBytes, 0, totalBytesReceived); if (ClientReceiveMessage.IndexOf("[FINAL]", StringComparison.Ordinal) > -1) { Console.WriteLine(ClientReceiveMessage); ClientReceiveMessage = ""; } client.BeginReceive(receivedBytes, 0, receivedBytes.Length, 0, new AsyncCallback(ReceiveCallback), client); } else { Console.WriteLine("服务端结束不再发送消息!" ); ClientReceiveMessage = ""; } }
Server
服务端循环异步Accept,可以接收多个client消息,并且马上回复。
static ManualResetEvent allDone = new ManualResetEvent(false); static void Main(string[] args) { Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Any, 2012)); listener.Listen(1); while (true) { allDone.Reset();
listener.BeginAccept(ar => { allDone.Set(); Socket MyServer = (Socket)ar.AsyncState; Socket service = MyServer.EndAccept(ar); byte[] receivedBytes = new byte[1024]; while (true) { string receivedValue = string.Empty; int numBytes = service.Receive(receivedBytes); receivedValue += Encoding.ASCII.GetString(receivedBytes,0, numBytes); if (receivedValue.IndexOf("[FINAL]", StringComparison.Ordinal) > -1) { Console.WriteLine("Received value: {0} from " + service.RemoteEndPoint, receivedValue); string replyValue = "Message successfully received.[FINAL]"; byte[] replyMessage = Encoding.ASCII.GetBytes(replyValue); service.Send(replyMessage); } } }, listener); allDone.WaitOne(); }
注意事项
1.Socket的Receive方法响应次数,是以缓冲数组的大小划分。如果数组大小为1024,消息为2048,Receive将会触发两次。作为接收方无法通过Receive来确定是否已完整接收,所以要对消息另作处理,例如在消息中增加[FINAL]来确定消息已发送完毕。
2.如果没有消息发送,接收方Receive方法会一直等待。但如果发送方调用Shutdown(SocketShutdown.Send)方法,接收方的Receive会马上返回0,所以在非来回传递消息的情况下,可以Shutdown方法来实现消息发送完毕。
3.可以设置ReceiveTimeout的值,超时会抛出异常,然而只能作用于Receive方法,对BeginReceive无效。