文档章节

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

o
 osc_ogi0qclx
发布于 2019/08/22 12:17
字数 1578
阅读 25
收藏 0

精选30+云产品,助力企业轻松上云!>>>

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

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}"));

  

  注:c#新手的随手笔记,方便以后学习和使用,如有不足和雷同,欢迎留言!谢谢!

o
粉丝 0
博文 500
码字总数 0
作品 0
私信 提问
加载中
请先登录后再评论。

暂无文章

jQuery获取select onChange的值 - jQuery get value of select onChange

问题: I was under the impression that I could get the value of a select input by doing this $(this).val(); 我的印象是我可以通过执行$(this).val();来获取选择输入的值$(this).val()......

javail
59分钟前
13
0
道翰天琼解密宇宙信息大脑三者最核心奥秘,破解认知智能基础理论(群聊形式)

三体论是探索研究宇宙,信息和人类大脑三者关系的理论体系。是认知智能的奠基理论体系之一。宇宙和信息,信息和人类大脑,人类大脑和宇宙,三者之间存在着某种未被完全揭示的奥秘。三体论的核...

jackli2020
今天
15
0
OSChina 周日乱弹 —— 这些照片能留存下来要感谢蛇不吃相机

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《28》- ゴンチチ 手机党少年们想听歌,请使劲儿戳(这里) @FalconChen :真得学...

小小编辑
今天
78
0
如何在视频中的对象后面添加图像

作者|PRATEEK JOSHI 编译|VK 来源|Analytics Vidhya 概述 在运动物体后面添加图像是一个典型的计算机视觉项目 了解如何使用传统的计算机视觉技术在视频中添加logo 介绍 我的一位同事向我提出...

人工智能遇见磐创
今天
14
0
UKUI Desktop Environment

install $ sudo add-apt-repository ppa:ubuntukylin-members/ukui3.0$ sudo apt upgrade or $ sudo apt-get install curl$ curl -sL 'https://keyserver.ubuntu.com/pks/lookup?&op=get&......

qwfys
今天
14
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部