Socket網絡編程(3)--兩端通訊

     上篇博文:http://www.cnblogs.com/wolf-sun/p/3329558.htmlhtml

     介紹了客戶端鏈接服務端,一對一,多對一的狀況,下面實現服務器接收消息的功能。LZ這些弄的比較慢,也是邊學習,邊動手實現的。具體步驟在註釋中寫的比較清楚,不懂的能夠留言,LZ會盡快回復。共同窗習,共同進步。數組

接收消息時機緩存

      何時接收消息?當服務器開始監聽,有客戶端鏈接,而且鏈接成功,此時負責通訊的Socket已經建立,此時就能夠接收消息了,能夠經過Socket的Receive()方法接收消息。服務器

 1        // 摘要:
 2         //     從綁定的 System.Net.Sockets.Socket 套接字接收數據,將數據存入接收緩衝區。
 3         //
 4         // 參數:
 5         //   buffer:
 6         //     System.Byte 類型的數組,它是存儲接收到的數據的位置。
 7         //
 8         // 返回結果:
 9         //     接收到的字節數。
10         //
11         // 異常:
12         //   System.ArgumentNullException:
13         //     buffer 爲 null。
14         //
15         //   System.Net.Sockets.SocketException:
16         //     試圖訪問套接字時發生錯誤。 有關更多信息,請參見備註部分。
17         //
18         //   System.ObjectDisposedException:
19         //     System.Net.Sockets.Socket 已關閉。
20         //
21         //   System.Security.SecurityException:
22         //     調用堆棧中的調用方沒有所需的權限。
23         public int Receive(byte[] buffer);
View Code

     上面代碼介紹了Receive方法接收參數及返回值。socket

 1  private void ListenConn(object o)
 2         {
 3             //將參數o 轉化爲監聽的socket
 4             Socket socketListener = o as Socket;
 5             //寫入循環 每個鏈接就建立一個通訊用的socket
 6             while (true)
 7             {
 8                 //當有客戶端鏈接成功 建立通訊用的socket
 9                 Socket connSocket = socketListener.Accept();
10                 string ip = connSocket.RemoteEndPoint.ToString();
11                 ShowMsg(ip + " " + DateTime.Now.ToString() + " 鏈接成功");
12                //建立一個新線程去接收消息
13                 Thread th = new Thread(ReceiveMsg);
14                 th.Start(connSocket);
15 
16             }
17 
18 }

接收消息的代碼:ide

 1   //接收客戶端的消息
 2         private void ReceiveMsg(object o)
 3         {
 4             Socket connSocket = o as Socket;
 5 
 6             //通訊用的socket鏈接成功 就能夠接收消息了
 7             byte[] buffer = new byte[1024 * 1024 * 5];//5M緩存
 8             while (true)
 9             {
10                 //count是當前接收的字節個數
11                 int count = connSocket.Receive(buffer);
12                 string ip = connSocket.RemoteEndPoint.ToString();
13                 //判斷接收到的字節個數 是0表示客戶端關閉了
14                 if (count > 0)
15                 {
16 
17                     //將字節轉換爲字符串
18                     string msg = Encoding.UTF8.GetString(buffer, 0, count);
19                     ShowMsg(ip + " " + DateTime.Now.ToString() + "\r\n" + msg);
20                 }
21                 else
22                 {
23                     //socket沒辦法發送空消息 若是收到空消息 客戶端關閉
24                     ShowMsg(ip + ":" + "斷開鏈接");
25                     connSocket.Close();
26                     break;
27 
28                 }
29 
30             }
31 
32         }

測試:仍然用telnet命令來測試:telnet 127.0.0.1 50000
學習

     測試結果:多對一,一對一,發送消息正常,關閉客戶端,服務端正常顯示哪一個客戶端斷開鏈接。測試

     服務器端全部代碼:this

  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.Net;
  8 using System.Net.Sockets;
  9 using System.Text;
 10 using System.Threading;
 11 using System.Threading.Tasks;
 12 using System.Windows.Forms;
 13 
 14 namespace Wolfy.ChatServer
 15 {
 16     public partial class Server : Form
 17     {
 18         public Server()
 19         {
 20             InitializeComponent();
 21             //不讓其檢查跨線程的操做
 22             Control.CheckForIllegalCrossThreadCalls = false;
 23         }
 24         //存放endpoin和通訊用的socket
 25         Dictionary<string, Socket> dic = new Dictionary<string, Socket>();
 26         private void btnSend_Click(object sender, EventArgs e)
 27         {
 28             ServerSendMsg(this.txtInputMsg.Text);
 29         }
 30         /// <summary>
 31         /// 服務器給客戶端發送消息
 32         /// </summary>
 33         private void ServerSendMsg(string msg)
 34         {
 35             //服務器給客戶端發消息
 36             string userkey = comboBoxEndpoint.Text;
 37             if (!string.IsNullOrEmpty(userkey))
 38             {
 39                 ShowMsg(msg);
 40                 byte[] buffer = Encoding.UTF8.GetBytes(msg);
 41                 dic[userkey].Send(buffer);
 42                 msg = "";
 43             }
 44             else
 45             {
 46                 MessageBox.Show("請選擇客戶端");
 47             }
 48         }
 49 
 50         private void btnStartService_Click(object sender, EventArgs e)
 51         {
 52             //服務器ip地址
 53             IPAddress ip = IPAddress.Parse(txtIPAddress.Text);
 54             //ip地址和端口
 55             IPEndPoint endpoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
 56             //建立用於監聽的socket
 57             Socket socketListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 58             //綁定ip和端口
 59             socketListener.Bind(endpoint);
 60             //開始監聽 限制鏈接數 最多能夠鏈接10個
 61             socketListener.Listen(10);
 62             ShowMsg("開始監聽......");
 63             //建立線程 去監聽鏈接
 64             Thread th = new Thread(ListenConn);
 65             //將線程變爲後臺線程
 66             th.IsBackground = true;
 67             th.Start(socketListener);
 68         }
 69         private void ListenConn(object o)
 70         {
 71             //將參數o 轉化爲監聽的socket
 72             Socket socketListener = o as Socket;
 73             //寫入循環 每個鏈接就建立一個通訊用的socket
 74             while (true)
 75             {
 76                 //當有客戶端鏈接成功 建立通訊用的socket
 77                 Socket connSocket = socketListener.Accept();
 78                 string ip = connSocket.RemoteEndPoint.ToString();
 79                 ShowMsg(ip + " " + DateTime.Now.ToString() + " 鏈接成功");
 80                 //鏈接成功後加入字典
 81                 dic.Add(ip, connSocket);
 82                 comboBoxEndpoint.Items.Add(ip);
 83                 //建立一個新線程去接收消息
 84                 Thread th = new Thread(ReceiveMsg);
 85                 th.Start(connSocket);
 86             }
 87 
 88         }
 89         //接收客戶端的消息
 90         private void ReceiveMsg(object o)
 91         {
 92             Socket connSocket = o as Socket;
 93 
 94             //通訊用的socket鏈接成功 就能夠接收消息了
 95             byte[] buffer = new byte[1024 * 1024 * 5];//5M緩存
 96             while (true)
 97             {
 98                 //count是當前接收的字節個數
 99                 int count = connSocket.Receive(buffer);
100                 string ip = connSocket.RemoteEndPoint.ToString();
101                 //判斷接收到的字節個數 是0表示客戶端關閉了
102                 if (count > 0)
103                 {
104                     //將字節轉換爲字符串
105                     string msg = Encoding.UTF8.GetString(buffer, 0, count);
106                     ShowMsg(ip + " " + DateTime.Now.ToString() + "\r\n" + msg);
107                 }
108                 else
109                 {
110                     //socket沒辦法發送空消息 若是收到空消息 客戶端關閉
111                     ShowMsg(ip + ":" + "斷開鏈接");
112                     connSocket.Close();
113                     break;
114                 }
115 
116             }
117 
118         }
119         /// <summary>
120         /// 提示信息輔助方法
121         /// </summary>
122         /// <param name="msg"></param>
123         private void ShowMsg(string msg)
124         {
125             this.txtMsgView.AppendText(msg + "\r\n");
126         }
127 
128         private void txtInputMsg_KeyUp(object sender, KeyEventArgs e)
129         {
130             //若是用戶按下了Enter鍵
131             if (e.KeyCode == Keys.Enter)
132             {
133                 //則調用 服務器向客戶端發送信息的方法
134                 ServerSendMsg(this.txtInputMsg.Text);
135             }
136         }
137     }
138 }
View Code

客戶端實現spa

     客戶端建立的socket即負責鏈接又負責通訊,因此這裏和服務端不一樣。客戶端鏈接、接收消息和發送消息代碼以下:

 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.Threading.Tasks;
 9 using System.Windows.Forms;
10 using System.Net.Sockets;
11 using System.Net;
12 using System.Threading;
13 namespace Wolf.ChatClient
14 {
15     public partial class Client : Form
16     {
17         public Client()
18         {
19             InitializeComponent();
20             //不讓檢查跨線程操做
21             Control.CheckForIllegalCrossThreadCalls = false;
22         }
23         Socket socket;
24         private void btnStartService_Click(object sender, EventArgs e)
25         {
26             //鏈接服務器的ip和端口
27             IPAddress ip = IPAddress.Parse(txtIPAddress.Text);
28             IPEndPoint endpoint = new IPEndPoint(ip, int.Parse(txtPort.Text));
29             //客戶端的socket即負責鏈接又負責通訊
30             socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
31             //鏈接服務器
32             socket.Connect(endpoint);
33             ShowMsg("鏈接成功......");
34             //和服務器鏈接成功後就能夠接收服務端的消息了
35             Thread th = new Thread(ReceiveMsg);
36             th.IsBackground = true;
37             th.Start();
38 
39         }
40         private void ReceiveMsg()
41         {
42             byte[] buffer = new byte[1024 * 1024 * 5];
43             while (true)
44             {
45                 int count = socket.Receive(buffer);
46                 string msg = Encoding.UTF8.GetString(buffer, 0, count);
47                 ShowMsg(this.txtIPAddress.Text + ":" + this.txtPort.Text + "  " + DateTime.Now.ToString() + "\r\n" + msg);
48             }
49         }
50         private void ShowMsg(string msg)
51         {
52             txtMsgView.AppendText(msg + "\r\n");
53         }
54         private void btnSend_Click(object sender, EventArgs e)
55         {
56             ClientSendMsg(this.txtInputMsg.Text);
57         }
58 
59         /// <summary>
60         /// 客戶端向服務端發送消息
61         /// </summary>
62         /// <param name="msg"></param>
63         private void ClientSendMsg(string msg)
64         {
65             //向服務端發送消息
66             if (socket != null)
67             {
68                 ShowMsg(msg);
69                 byte[] buffer = Encoding.UTF8.GetBytes(msg);
70                 socket.Send(buffer);
71                 msg = "";
72             }
73             else
74             {
75                 ShowMsg("<<<<請先鏈接服務器>>>");
76             }
77         }
78 
79         private void txtInputMsg_KeyUp(object sender, KeyEventArgs e)
80         {
81             //若是用戶按下了Enter鍵
82             if (e.KeyCode == Keys.Enter)
83             {
84                 //則調用 服務器向客戶端發送信息的方法
85                 ClientSendMsg(this.txtInputMsg.Text);
86             }
87         }
88 
89         private void Client_FormClosing(object sender, FormClosingEventArgs e)
90         {
91             //客戶端關閉 關閉socket
92             socket.Shutdown(SocketShutdown.Both);
93         }
94     }
95 }
View Code

測試結果:


 結語:

       邊學習,邊動手,實現了兩端通訊,目前支持一對一,多對一通訊功能,代碼中針對關閉客戶端的狀況還有bug,有待進一步修改。

相關文章
相關標籤/搜索