分享

c# TCP/IP协议利用Socket的简单通信

 小世界的野孩子 2021-04-23

完全是基础,新手可以随意看看,大牛可以关闭浏览页了,哈哈。

TCP/IP协议

TCP/IP是一系列网络通信协议的统称,其中最核心的两个协议是TCP和IP。TCP称为传输控制协议,IP称为互联网络协议。

网络分层除了OSI模型分层,还有TCP/IP模型分层,将网络划分为四层,应用层、传输层、网际层、网络接口层。TCP/IP模型分层是OSI模型分层的浓缩版

OSI模型和TCP/IP网络分层的对应结构及TCP/IP部分协议族,

 

TCP三次握手

第一次握手:建立连接。客户端发送连接请求报文段,将SYN位置为1,Sequence Number为x;然后,客户端进入SYN_SEND状态,等待服务器的确认;
第二次握手:服务器收到SYN报文段。服务器收到客户端的SYN报文段,需要对这个SYN报文段进行确认,设置Acknowledgment Number为x+1(Sequence Number+1);同时,自己自己还要发送SYN请求信息,将SYN位置为1,Sequence Number为y;服务器端将上述所有信息放到一个报文段(即SYN+ACK报文段)中,一并发送给客户端,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1,向服务器发送ACK报文段,这个报文段发送完毕以后,客户端和服务器端都进入ESTABLISHED状态,完成TCP三次握手。

三次握手图解

在此基础上,socket连接过程:

服务器监听:服务器端socket并不定位具体的客户端socket,而是处于等待监听状态,实时监控网络状态。

客户端请求:客户端clientSocket发送连接请求,目标是服务器的serverSocket。为此,clientSocket必须知道serverSocket的地址和端口号,进行扫描发出连接请求。

连接确认:当服务器socket监听到或者是受到客户端socket的连接请求时,服务器就响应客户端的请求,建议一个新的socket,把服务器socket发送给客户端,一旦客户端确认连接,则连接建立。

注:在连接确认阶段:服务器socket即使在和一个客户端socket建立连接后,还在处于监听状态,仍然可以接收到其他客户端的连接请求,这也是一对多产生的原因。

socket连接原理知道了,此处编写最基本最简单的socket通信:

客户端代码:

     /// <summary>
        /// 客户端发送与服务端的连接请求,创建与之通信用的Socket
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnLink_Click(object sender, EventArgs e)
        {
            try
            {                   
          //定义一个用于请求连接服务器的IP和端口号
          IPEndPoint ip = new IPEndPoint(IPAddress.Parse(txtIp.Text), Convert.ToInt32(txtPort.Text));//txtIP:IP地址;txtPort:端口号
          //定义一个套接字用于请求连接服务器,包含三个参数(IP4寻址协议,流式连接,Tcp协议)
          socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

          //请求连接服务端 
          clientSocket.Connect(ip); 
          //创建一个通信线程,避免阻塞主线程 
          Thread th = new Thread(CRecive);
          //设置为后台线程,随着主线程退出而退出
                th.IsBackground = true;
          //启动线程
                th.Start(clientSocket);
          //显示与服务端连接情况
                ShowMsg($"{clientSocket.RemoteEndPoint.ToString()}:已连接");
            }
            catch (Exception ex)
            {
          //提示套接字监听异常
                ShowMsg($"网络错误");
            }
        }

        /// <summary>
        /// 客户端不停的接收服务端发送过来的消息
        /// </summary>
        /// <param name="o"></param>
        void CRecive(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                try
                {
                    //创建一个内存缓冲区,其大小为1024*1024字节  即1M
                    byte[] buffer = new byte[1024 * 1024];
                    //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
                    int length = socketSend.Receive(buffer);
                    if (length == 0)
                    {
                        ShowMsg($"{socketSend.RemoteEndPoint.ToString()}:已断开连接");
                        break;
                    }
            //将机器接受到的字节数组转换为人可以读懂的字符串
                    string str = Encoding.UTF8.GetString(buffer, 0, length);
            //将发送的字符串信息附加到ShowMsg上
                    ShowMsg($"Ta({socketSend.RemoteEndPoint.ToString()}):{str}");
                }
                catch (Exception ex)
                { }

            }
        }

  

  客户端向服务端发送数据:

clientSocket.Send(Encoding.UTF8.GetBytes($"{txtWrite.Text}"));

  

服务端代码:

      /// <summary>
        /// 开启监听,等待客户端连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMonitor_Click(object sender, EventArgs e)
        {
            try
            {
                //定义一个套接字用于监听客户端发来的消息,包含三个参数(IP4寻址协议,流式连接,Tcp协议)
                socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //服务端发送信息需要一个IP地址和端口号
                IPAddress ip = IPAddress.Parse(txtIp.Text);//IPAddress.Any;
                                                           //将IP地址和端口号绑定到网络节点point上
                IPEndPoint point = new IPEndPoint(ip, Convert.ToInt32(txtPort.Text));
                //监听绑定的网络节点
                socketWatch.Bind(point);
                ShowMsg("开始监听。。。");
                //将套接字的监听队列长度限制为10           
                socketWatch.Listen(10);
                //负责监听客户端的线程:创建一个监听线程
                Thread th = new Thread(SListen);
                //将窗体线程设置为与后台同步,随着主线程结束而结束
                th.IsBackground = true;
                //启动线程
                th.Start(socketWatch);
            }
            catch (Exception ex)
            { }

        }
        /// <summary>
        /// 等待客户端的连接 并且创建与之通信用的Socket
        /// </summary>
        /// <param name="o"></param>
        void SListen(object o)
        {
            Socket socketWatch = o as Socket;
            while (true)
            {
                try
                {
                    //等待客户端的连接,并且创建与之通信用的Socket
                    Socket serverSocket = socketWatch.Accept();
                    //获取客户端网络结点号
                    string socketIP = serverSocket.RemoteEndPoint.ToString();
                    ShowMsg($"{socketIP}:已连接");
                    //创建一个通信线程,避免阻塞主线程
                    Thread th = new Thread(SRecive);
                    th.IsBackground = true;
                    th.Start(serverSocket);
                }
                catch
                { }
            }
        }
        /// <summary>
        /// 服务端不停的接收客户端发送过来的消息
        /// </summary>
        /// <param name="o"></param>
        void SRecive(object o)
        {
            Socket socketSend = o as Socket;
            while (true)
            {
                //将接收到的信息存入到内存缓冲区,并返回其字节数组的长度
                try
                {
                    //创建一个内存缓冲区,其大小为1024*1024字节  即1M
                    byte[] buffer = new byte[1024 * 1024];
                    //接收客户端发送过来的消息
                    int length = socketSend.Receive(buffer);
                    if (length == 0)
                    {
                        ShowMsg($"{socketSend.RemoteEndPoint.ToString()}:已断开连接");
                        break;
                    }
                    //将机器接受到的字节数组转换为人可以读懂的字符串
                    string str = Encoding.UTF8.GetString(buffer, 0, length);
                    //将发送的字符串信息附加到ShowMsg上
                    ShowMsg($"Ta({socketSend.RemoteEndPoint.ToString()}):{str}");
                }
                catch (Exception ex) { }
            }
        }

  

  

 服务端向已连接的客户端发送数据: 

serverSocket.Send(Encoding.UTF8.GetBytes($"{txtWrite.Text}"));

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多