前言
Socket的英文原义是“孔”或“插座”,其实在网络编程中Socket就是这个意思,就像我们打电话,要首先知道对方的手机号一样,这个手机号就相当于一个Socket号、一个插座,在网络编程中就是ip+端口作为一个插座。
实现
System.Net.Sockets命名空间下提供了Socket类,使.net下Socket变得很简单,Socket实现点对点通信有两种方式,一种是用服务器转接,所有的客户端都发送到服务端,客户端只做客户端;另一种是客户端既是服务端又是服务端,就是既监听又发送信息。这篇就用第二种方式简单实现下,首先看下简单示意图:
发送信息代码:
1 string message = txtMsg.Text.Trim(); 2 socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 3 string remoteIp = this.txtRemoteIP.Text; 4 string remotePort = this.txtRemotePort.Text; 5 int serverPort = Convert.ToInt32(remotePort); 6 IPAddress serverIp = IPAddress.Parse(remoteIp); 7 IPEndPoint remoteIep = new IPEndPoint(serverIp, serverPort); 8 socketClient.Connect(remoteIep); 9 toolStripStatusLabel1.Text = "与远程计算机" + remoteIp + ":" + remotePort + "建立连接!"; 10 11 byte[] byteMessage = Encoding.Default.GetBytes(message); 12 socketClient.Send(byteMessage); 13 14 IPHostEntry host = Dns.GetHostEntry(GetServerIP()); 15 string HostName = host.HostName; 16 17 //发送信息 18 string time1 = DateTime.Now.ToString(); 19 listBox1.Items.Add(GetServerIP().ToString() + "(" + HostName + ") " + time1); 20 listBox1.Items.Add(message); 21 22 socketClient.Shutdown(SocketShutdown.Both); 23 socketClient.Close();
IPEndPoint从这个单词的意思就可以看出是一个远端的地址信息,Connect方法根据这个地址建立链接,然后调用Send方法向远端发送信息,发送完信息之后要使用Shutdown指向当前Socket是否接受发送消息,下面列出SocketShutdown的枚举值:
值 |
描述 |
---|---|
Send |
禁用此 Socket 上的发送。 |
Receive |
禁用此 Socket 上的接收。 |
Both |
同时禁用此 Socket 上的发送和接收。 |
Shutdown在msdn上解释是这样的:如果当前使用的是面向连接的Socket,则必须先调用 Shutdown 方法,然后才能关闭Socket。这可以确保在已连接的套接字关闭之前,已发送和接收该套接字上的所有数据。Shutdown也是关闭的意思,其实关于Shutdown和Close我在网上找了很多资料,关于Shutdown解释的云里雾里,不是很明白,我这样理解不知道对不对,上面打电话的例子,按号码打通电话说完话按下挂机键,Shutdown的意思这样,确保信息已经发送。
监听代码:
1 socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 2 3 IPAddress ServerIp = GetServerIP(); 4 IPEndPoint iep = new IPEndPoint(ServerIp, port); 5 socketServer.Bind(iep); 6 7 while (true) 8 { 9 try 10 { 11 socketServer.Listen(5); 12 allDone.Reset(); 13 socketServer.BeginAccept(new AsyncCallback(AcceptCallback), socketServer); 14 allDone.WaitOne(); 15 } 16 catch (SocketException ex) 17 { 18 toolStripStatusLabel1.Text += ex.ToString(); 19 } 20 }
Bind与本机绑定开通这个“号码”以方便别人可以打进来,Listen(5)5的意思是最大的监听数,BeginAccept的意思是开始一个异步操作来接受一个传入的连接尝试,以异步方式接受连接将使您能够在单独的执行线程中发送和接收数据,回调方法使用EndAccept,并返回新的Socket对象。
1 //异步连接回调函数 2 public void AcceptCallback(IAsyncResult ar) 3 { 4 Socket listener = (Socket)ar.AsyncState; 5 Socket client = listener.EndAccept(ar); 6 allDone.Set(); 7 StateObject state = new StateObject(); 8 state.workSocket = client; 9 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state); 10 } 11 12 //异步接收回调函数 13 public void readCallback(IAsyncResult ar) 14 { 15 StateObject state = (StateObject)ar.AsyncState; 16 Socket handler = state.workSocket; 17 int bytesRead = handler.EndReceive(ar); 18 if (bytesRead > 0) 19 { 20 string strmsg = Encoding.Default.GetString(state.buffer, 0, bytesRead); 21 22 //远端信息 23 EndPoint tempRemoteEP = handler.RemoteEndPoint; 24 IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP; 25 IPHostEntry host = Dns.GetHostByAddress(tempRemoteIP.Address); 26 string HostName = host.HostName; 27 28 string ip = tempRemoteIP.Address.ToString() + "(" + HostName + ") " + DateTime.Now.ToString(); 29 if (listBox1.InvokeRequired) 30 { 31 MyDelegate md; 32 md = new MyDelegate(ChangeText); 33 listBox1.Invoke(md, ip, strmsg); 34 } 35 } 36 }
listener.EndAccept(ar)和handler.EndReceive(ar)取回远端Socket对象,这边注意下获取IPHostEntry对象并不是用GetHostEntry方法,而是GetHostByAddress方法,使用GetHostEntry方法会产生异常,异步调用传输对象StateObject:
1 //异步传递的状态对象 2 public class StateObject 3 { 4 public Socket workSocket = null; 5 public const int BufferSize = 1024; 6 public byte[] buffer = new byte[BufferSize]; 7 }
运行截图:
完整代码:
程序下载:Socket点对点通信.rar
本文转自田园里的蟋蟀博客园博客,原文链接:http://www.cnblogs.com/xishuai/p/3540200.html,如需转载请自行联系原作者