zoukankan      html  css  js  c++  java
  • Socket网络编程(3)--两端通信

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

         介绍了客户端连接服务端,一对一,多对一的情况,下面实现服务器接收消息的功能。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方法接收参数及返回值。

     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 }

    接收消息的代码:

     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() + "
    " + 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

         测试结果:多对一,一对一,发送消息正常,关闭客户端,服务端正常显示哪个客户端断开连接。

         服务器端所有代码:

      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() + "
    " + 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 + "
    ");
    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

    客户端实现

         客户端创建的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() + "
    " + msg);
    48             }
    49         }
    50         private void ShowMsg(string msg)
    51         {
    52             txtMsgView.AppendText(msg + "
    ");
    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,有待进一步修改。

  • 相关阅读:
    浙大版《C语言程序设计(第3版)》题目集 --总结
    | C语言I作业09
    c语言课本及pta作业中运用到的程序思维
    | C语言I作业08
    团队作业(四):描述设计
    实验三《敏捷开发与XP实践》_实验报告
    MyOD(课下作业,选做)
    实验二《面向对象程序设计》_实验报告
    20175226 2018-2019-2《java程序设计》结对编程-四则运算(第二周-阶段总结)
    20175226 类定义
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/3330221.html
Copyright © 2011-2022 走看看