基於socket實現的簡單的聊天程序


  記得八年前第一次使用socket做的一個五子棋程序,需要序列化棋子對象,傳遞到對方的電腦上。 一個偶然的機會,第二次使用socket做點事情。先看聊天服務器端的實現:

     服務器端要實現以下功能:

     1、啟動服務,開啟監聽

     2、持續不斷地接收消息

     3、發送消息

    啟動服務,創建監聽socket,綁定Ip和端口:

 1         /// <summary>
 2         /// 啟動服務
 3         /// </summary>
 4         private void Start()
 5         {
 6             socketwatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 7 
 8             IPAddress address = IPAddress.Parse("10.0.0.31");
 9 
10             IPEndPoint point = new IPEndPoint(address, 8025);
11 
12             socketwatch.Bind(point);
13 
14             //將套接字的監聽隊列長度限制為20  
15             socketwatch.Listen(20);
16 
17             //創建一個監聽線程  
18             threadwatch = new Thread(watchconnecting);
19 
20             threadwatch.IsBackground = true;
21 
22             threadwatch.Start();
23         }

創建接收數據的Socket:

 1  //監聽客戶端發來的請求  
 2         private void watchconnecting()
 3         {
 4             Socket connection = null;
 5             while (true)  //持續不斷監聽客戶端發來的請求     
 6             {
 7                 try
 8                 {
 9                     connection = socketwatch.Accept();
10                 }
11                 catch (Exception ex)
12                 {
13                     MessageBox.Show(ex.Message); //提示套接字監聽異常     
14                     break;
15                 }
16                 //獲取客戶端的IP和端口號  
17                 IPAddress clientIP = (connection.RemoteEndPoint as IPEndPoint).Address;
18                 int clientPort = (connection.RemoteEndPoint as IPEndPoint).Port;
19 
20                 //讓客戶顯示"連接成功的"的信息  
21                 string sendmsg = "連接服務端成功!\r\n" + "本地IP:" + clientIP + ",本地端口" + clientPort.ToString();
22                 byte[] arrSendMsg = Encoding.UTF8.GetBytes(sendmsg);
23                 connection.Send(arrSendMsg);
24 
25                 RemoteEndPoint = connection.RemoteEndPoint.ToString(); //客戶端網絡結點號  
26                 dic.Add(RemoteEndPoint, connection);    //添加客戶端信息  
27 
28                 IPEndPoint netpoint = connection.RemoteEndPoint as IPEndPoint;
29 
30                 //創建一個通信線程      
31                 ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
32                 Thread thread = new Thread(pts);
33                 thread.IsBackground = true;//設置為后台線程,隨着主線程退出而退出     
34                 //啟動線程     
35                 thread.Start(connection);
36             }
37         }

socketwatch.Accept()
會創建一個新的socket,它用來負責和某個客戶端的通訊。

接收數據:
 1         private void recv(object socketclientpara)
 2         {
 3 
 4             Socket socketServer = socketclientpara as Socket;
 5             while (true)
 6             {
 7                 byte[] arrServerRecMsg = new byte[1024 * 1024];
 8                 try
 9                 {
10                     int length = socketServer.Receive(arrServerRecMsg);
11 
12                     string strSRecMsg = Encoding.UTF8.GetString(arrServerRecMsg, 0, length);
13 
14                     this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
15                               (ThreadStart)delegate()
16                               {
17                                   MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strSRecMsg, IdentityName = socketServer.RemoteEndPoint.ToString() });
18                               });
19                 }
20                 catch (Exception ex)
21                 {
22                     MessageBox.Show(ex.Message);
23                     socketServer.Close();
24                     break;
25                 }
26             }
27         }

把從客戶端接收過來的字節流變為字符串,然后添加到頁面上。

發送消息:

 1         private static object lockPool = new object();
 2         public static ObservableCollection<Message> MessagePool = new ObservableCollection<Message>();
 3         private void send_Click(object sender, RoutedEventArgs e)
 4         {
 5             string msg = this.message.Text;
 6 
 7             this.message.Clear();
 8 
 9             lock (lockPool)
10             {
11                 MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = msg, IdentityName = "wbq" });
12             }
13 
14             string sendMsg = msg; 
15             byte[] bytes = System.Text.Encoding.UTF8.GetBytes(sendMsg);
16 
17             if (dic.Count > 0)
18                 dic.First().Value.Send(bytes);
19         }
dic.First().Value.Send,從字典中獲取到之前創建好的通訊socket,然后調用send方法。

客戶端需要實現以下功能:
1、和服務器建立連接
2、接收數據
3、發送數據

建立連接:
 1    private void Start()
 2         {
 3 
 4             //定義一個套接字監聽  
 5             socketclient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 6 
 7 
 8            var servers= GetServers();
 9 
10 
11            if (servers.Count > 0)
12            {
13 
14                //獲取文本框中的IP地址  
15                IPAddress address = IPAddress.Parse(servers.First().IPToPing);
16 
17                //將獲取的IP地址和端口號綁定在網絡節點上  
18                IPEndPoint point = new IPEndPoint(address, int.Parse(servers.First().Port));
19 
20                try
21                {
22                    //客戶端套接字連接到網絡節點上,用的是Connect  
23                    socketclient.Connect(point);
24                }
25                catch (Exception)
26                {
27                    //MessageBox.  
28                    MessageBox.Show("連接失敗\r\n");
29                    return;
30                }
31 
32                threadclient = new Thread(recv);
33 
34                threadclient.IsBackground = true;
35 
36                threadclient.Start();
37            }
38         }

 

接收消息:

 1        // 接收服務端發來信息的方法    
 2         private void recv()//  
 3         {
 4             while (true)//持續監聽服務端發來的消息  
 5             {
 6                 try
 7                 {
 8                     //定義一個1M的內存緩沖區,用於臨時性存儲接收到的消息  
 9                     byte[] arrRecvmsg = new byte[1024 * 1024];
10 
11                     //將客戶端套接字接收到的數據存入內存緩沖區,並獲取長度  
12                     int length = socketclient.Receive(arrRecvmsg);
13 
14                     //將套接字獲取到的字符數組轉換為人可以看懂的字符串  
15                     string strRevMsg = Encoding.UTF8.GetString(arrRecvmsg, 0, length);
16 
17                     this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
18                                (ThreadStart)delegate()
19                                {
20                                    MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strRevMsg, IdentityName = socketclient.RemoteEndPoint.ToString() });
21                                });
22                 }
23                 catch (Exception ex)
24                 {
25                     MessageBox.Show("遠程服務器已經中斷連接" + ex.Message);
26                     break;
27                 }
28             }
29         }
發送消息:
 1         private void send_Click(object sender, RoutedEventArgs e)
 2         {
 3             string strRevMsg = this.message.Text;
 4             this.message.Clear();
 5 
 6             lock (lockPool)
 7             {
 8                 MessagePool.Insert(MessagePool.Count, new Message() { MessageInfo = strRevMsg, IdentityName = "我(" + socketclient.LocalEndPoint.ToString() + ")" });
 9             }
10 
11             //將輸入的內容字符串轉換為機器可以識別的字節數組     
12             byte[] arrClientSendMsg = Encoding.UTF8.GetBytes(strRevMsg);
13             //調用客戶端套接字發送字節數組     
14             socketclient.Send(arrClientSendMsg);
15         }
經過和同事的測試,可以實現簡單的文字聊天,此代碼僅為測試代碼,若要用於實際的項目中,需要很大改進,比如socket異步建立,消息接收和發送等等。












免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM