基于socket实现的简单的聊天程序

C#

浏览数:70

2019-9-18

AD:资源代下载服务

  记得八年前第一次使用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异步建立,消息接收和发送等等。











作者:micDavid