前言
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 }
運行截圖:
完整代碼:

1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 10 using System.Threading; 11 using System.Net; 12 using System.Net.Sockets; 13 14 namespace ClientSocket 15 { 16 public partial class Form1 : Form 17 { 18 Socket socketClient; 19 Thread mythread;//創建線程 20 Socket socketServer; 21 int port = 8080;//定義偵聽端口號 22 public static ManualResetEvent allDone = new ManualResetEvent(false); 23 public delegate void MyDelegate(string ip,string message); 24 25 public Form1() 26 { 27 InitializeComponent(); 28 } 29 private void Form1_Load(object sender, EventArgs e) 30 { 31 mythread = new Thread(new ThreadStart(BeginListen)); 32 mythread.Start(); 33 34 txtRemoteIP.Text = GetServerIP().ToString(); 35 } 36 37 #region server 38 //獲取本機IP地址 39 public static IPAddress GetServerIP() 40 { 41 IPHostEntry ieh = Dns.GetHostEntry(Dns.GetHostName()); 42 foreach (IPAddress item in ieh.AddressList) 43 { 44 if (item.ToString().IndexOf("192.168.0.")>=0) 45 { 46 return item; 47 } 48 } 49 return null; 50 } 51 52 //異步傳遞的狀態對象 53 public class StateObject 54 { 55 public Socket workSocket = null; 56 public const int BufferSize = 1024; 57 public byte[] buffer = new byte[BufferSize]; 58 } 59 60 //監聽 61 private void BeginListen() 62 { 63 socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 64 65 IPAddress ServerIp = GetServerIP(); 66 IPEndPoint iep = new IPEndPoint(ServerIp, port); 67 socketServer.Bind(iep); 68 69 while (true) 70 { 71 try 72 { 73 socketServer.Listen(5); 74 allDone.Reset(); 75 socketServer.BeginAccept(new AsyncCallback(AcceptCallback), socketServer); 76 allDone.WaitOne(); 77 } 78 catch (SocketException ex) 79 { 80 toolStripStatusLabel1.Text += ex.ToString(); 81 } 82 } 83 } 84 85 //異步連接回調函數 86 public void AcceptCallback(IAsyncResult ar) 87 { 88 Socket listener = (Socket)ar.AsyncState; 89 Socket client = listener.EndAccept(ar); 90 allDone.Set(); 91 StateObject state = new StateObject(); 92 state.workSocket = client; 93 client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(readCallback), state); 94 } 95 96 //異步接收回調函數 97 public void readCallback(IAsyncResult ar) 98 { 99 StateObject state = (StateObject)ar.AsyncState; 100 Socket handler = state.workSocket; 101 int bytesRead = handler.EndReceive(ar); 102 if (bytesRead > 0) 103 { 104 string strmsg = Encoding.Default.GetString(state.buffer, 0, bytesRead); 105 106 //遠端信息 107 EndPoint tempRemoteEP = handler.RemoteEndPoint; 108 IPEndPoint tempRemoteIP = (IPEndPoint)tempRemoteEP; 109 IPHostEntry host = Dns.GetHostByAddress(tempRemoteIP.Address); 110 string HostName = host.HostName; 111 112 string ip = tempRemoteIP.Address.ToString() + "(" + HostName + ") " + DateTime.Now.ToString(); 113 if (listBox1.InvokeRequired) 114 { 115 MyDelegate md; 116 md = new MyDelegate(ChangeText); 117 listBox1.Invoke(md, ip, strmsg); 118 } 119 } 120 } 121 122 public void ChangeText(string ip,string message) 123 { 124 listBox1.Items.Add(ip); 125 listBox1.Items.Add(message); 126 } 127 128 #endregion 129 130 #region client 131 //發送信息 132 private void btn_Send_Click(object sender, EventArgs e) 133 { 134 try 135 { 136 string message = txtMsg.Text.Trim(); 137 socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 138 string remoteIp = this.txtRemoteIP.Text; 139 string remotePort = this.txtRemotePort.Text; 140 int serverPort = Convert.ToInt32(remotePort); 141 IPAddress serverIp = IPAddress.Parse(remoteIp); 142 IPEndPoint remoteIep = new IPEndPoint(serverIp, serverPort); 143 socketClient.Connect(remoteIep); 144 toolStripStatusLabel1.Text = "與遠程計算機" + remoteIp + ":" + remotePort + "建立連接!"; 145 146 byte[] byteMessage = Encoding.Default.GetBytes(message); 147 socketClient.Send(byteMessage); 148 149 IPHostEntry host = Dns.GetHostEntry(GetServerIP()); 150 string HostName = host.HostName; 151 152 //發送信息 153 string time1 = DateTime.Now.ToString(); 154 listBox1.Items.Add(GetServerIP().ToString() + "(" + HostName + ") " + time1); 155 listBox1.Items.Add(message); 156 157 socketClient.Shutdown(SocketShutdown.Both); 158 socketClient.Close(); 159 } 160 catch 161 { 162 toolStripStatusLabel1.Text = "無法連接到目標計算機!"; 163 return; 164 } 165 } 166 167 private void btnClose_Click(object sender, EventArgs e) 168 { 169 Application.Exit(); 170 } 171 #endregion 172 } 173 }
程序下載:Socket點對點通信.rar