TCP 学习笔记

Win + R   打开控制台输入CMD  打开小黑窗, 输入ipconfig  查询本机地址

 

“外网IP是全世界唯一的IP地址,仅分配给一个网络设备。而内网IP是由路由器分配给每一部内部使用的IP地址,而内网的所有用户都是通过同一个外网IP地址进行上网的,而内网的IP地址每个人的都不一样,Internet上的用户也无法直接访问到内网用户。简单来说呢,外网IP就是标示了您在整个互联网上的地址,就相当于小区的地址,而内网IP呢,就是标识着您在局域网里面的地址,也就是小区内的几栋几楼几号房子。

内网IP地址一般是192.168开头 ,连接到wifi或网线的每个设备都有自己的一个内网ip

外网可以理解为公司的总网,也就是牵的网线里的网络

而内网是由路由器为每个设备分配的ip

端口号就是用来决定将消息传给同一内网IP下的某个程序 

三次握手,四次挥手

TCP 协议比较稳定,需要与接收方建立连接,可以确保数据不会丢失,可以保证数据发送的是否正确,需得到接收方的返回,如果在一定时间内没有收到回应则会重新发送。

UDP 速度快,但是不稳定安全,不用建立连接 (只管发,不管接,可能会被拦截,或断掉)

三次握手: 建立连接

四次挥手:断开连接

 IPv6的出现是因为IPv4不够用了 

 

 TCP 用Stream 流通信比较稳定,  创建服务端代码如下

using System.Net.Sockets;
using System.Net;
namespace TCP学习
{
    class Program
    {
        static void Main(string[] args)
        {
            StartServerAsync();
            Console.ReadKey();
        }
        static void StartServerAsync()
        {
            Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //本机IP: 192.168.1.195 /127.0.0.1(127永远代表本机IP)  //196不是固定的,重启后或一定时间后路由器会重新分配IP
            //IPAddress xxx.xxx.xxx.xxx  IPEndPoint xxx.xxx.xxx.xxx:port
            //IPAddress iPAddress = new IPAddress(new byte[] { 192, 168, 1, 195 });
            IPAddress iPAddress = IPAddress.Parse("192.168.1.195");//推荐
            IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 88);
            serverSocket.Bind(iPEndPoint); //绑定IP和端口号
            serverSocket.Listen(0);   //开始监听端口号,参数为监听队列长度,
                                      //Listen(10)指超过10个后的消息不接收,设置为0不限制

            //同步接收客户端的连接(旧方法)
            //Socket clientSocket = serverSocket.Accept(); // 接收一个客户端链接 程序在这里暂停,直到有客户端连接
            //向链接的客户端发送消息
            //string msg = "Hello你好";
            //byte[] msgB = System.Text.Encoding.UTF8.GetBytes(msg); //把字符串转为字节数组
            //clientSocket.Send(msgB);
            //dataBuffer = new byte[10240];

            //异步接收客户端的消息,不影响下面的代码执行//当接收到客户端消息时才调用回调方法,最后一个参数是回调方法的参数
            //clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);


            //同步接收客户端的消息(旧方法)
            //byte[] msgC = new byte[1024];
            //int count = clientSocket.Receive(msgC); //用msgC储存接收的数据.//程序在这里暂停,等待客户端发送消息//返回值是接收到的数据的长度
            //string msgD = System.Text.Encoding.UTF8.GetString(msgC, 0, count); //把前count个的字节数组数据转为字符串                                                           //从0开始读取count个数据
            //Console.WriteLine(msgD);

            //Console.ReadKey();
            //clientSocket.Close(); //关闭的和客户端的一个连接
            //serverSocket.Close(); //关闭自身的连接,停服

            serverSocket.BeginAccept(AcceptCallBack, serverSocket);

            //到目前为止 服务器端已经可以处理多个客户端的连接,也可以处理多个来自同一个客户端的消息 最终处理来自多个客户端的多个消息
        }
        static byte[] dataBuffer = new byte[1024];

        static void AcceptCallBack(IAsyncResult ar)
        {
            Socket serverSocket = ar.AsyncState as Socket;
            Socket clientSocket = serverSocket.EndAccept(ar);
            string msg = "Hello你好";
            byte[] msgB = System.Text.Encoding.UTF8.GetBytes(msg);
            clientSocket.Send(msgB);
            clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
            serverSocket.BeginAccept(AcceptCallBack, serverSocket);
        }
        static void ReceiveCallBack(IAsyncResult ar)
        {
            Socket clientSocket = null;
            try    //try 异常捕捉是为了当客户端异常关闭(非正常关闭)时,让所持有的客户端被释放且无法用该客户端继续接收消息
            {
                clientSocket = (Socket)ar.AsyncState;
                int count = clientSocket.EndReceive(ar);  //客户端如果发送"" 是接收不到的,当客户端Close时,会收到客户端的空消息,个数为0
                //所以当客户端的消息个数为0时,客户端主动断开(正常关闭)了
                if (count == 0)
                {
                    clientSocket.Close();
                    return;
                }
                string msg = System.Text.Encoding.UTF8.GetString(dataBuffer, 0, count);
                Console.WriteLine("从客户端接收到数据:" + msg);
                clientSocket.BeginReceive(dataBuffer, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                if (clientSocket != null)
                {
                    clientSocket.Close();
                }
            }
            finally
            {
               
            }
        }
    }
    
}

创建客户端代码如下

using System.Net.Sockets;
using System.Net;
namespace TCP客户端
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //客户端只需要和服务端建立连接 ,不需要绑定Bind
            Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            clientSocket.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.195"),88));
            //接收这部分和服务器端一样
            byte[] msgC = new byte[1024];
            int count = clientSocket.Receive(msgC); //接收服务端的消息,用msgC储存接收的数据.
                                                    //返回值是接收到的数据的长度
                                                    // 执行到Receive程序会暂停,直到接收到服务端的消息 
            string msgD = System.Text.Encoding.UTF8.GetString(msgC, 0, count); //把前count个的字节数组数据转为字符串
                                                                               //从0开始读取count个数据
            Console.WriteLine(msgD);

            while (true)
            {
                string str = Console.ReadLine();
                if (str == "Close")   //客户端发送Close 主动要求断开连接
                { 
                    clientSocket.Close();
                    return;
                }
                clientSocket.Send(System.Text.Encoding.UTF8.GetBytes(str));
            }
            Console.ReadKey();
            clientSocket.Close();
        }
    }
}

同步方式:Accept Connect   /   Receive

异步方式:BeginAccept  EndAccept  /    BeginReceive    EndReceive  

效果如下,多客户端连接一个服务器

粘包和分包

粘包 :当发送数据比较频繁,且数据量小,TCP  在你点发送时不会立马把数据发出去,而是等很多条数据达到一定量整合到一起发出去,服务器端或客户端执行一次Receive就可以收到多条消息的整合,如果点一次发一次会造成数据传输性能开销,

 粘包虽然会粘在一起,但是到达的先后顺序是不会变的

分包: 当数据量很大,上千上万的数据,TCP会分几次发送,大包占用网速,运送慢, 占用时间长,发送失败还要重新发送,服务器端或客户端执行一次Receive可能收到的不是一个完整的消息,而是被分割的消息段

我们定义的数组是1024字节,所以一次消息只能发1024字节数据,数据超过了就要分包发送,

可以加大每次发送的字节容量大小来避免分包(前提是异步,如果是同步,即使容量大也会分包),不过一般不考虑,很少有一次会发送那么大的数据,应该考虑的是粘包问题,因为游戏交互每次发送数据的量很小。次数也多

 处理粘包问题:

一个字符占一个字节 ,一个空格占用一个字节 ,一个汉字占3个字节

  int count = 15686;
            byte[] data = BitConverter.GetBytes(count);//支持值类型参数
            foreach (byte b in data)
            {
                Console.Write(b + ":");  //可以确保数据头只占用int32  4个字节
            }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/31240.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SQL 基础语句

SQL 基础语句 DDL Data Definition Language 数据定义语言创建 create删除 drop修改 alter清空 truncate show tables ; --查看所有表: drop database db1; --删除数据库 create database db1 default character set utf8; --创建数据库 use databas…

十大基础算法

一、选择排序 过程简单描述: 首先,找到数组中最小的那个元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。其次,在剩下的元素中找到最小的元素,将它与数组的第二…

C++【STL】之priority_queue学习

优先级队列 优先级队列priority_queue也是STL库中容器适配器的一种,常用于进行数据优先级的处理,说到这儿是不是发现有些熟悉,没错它和我们之前讲解的堆本质上就是一个东西,底层都是数组存储的完全二叉树,它在STL库中…

设计模式(二十二):行为型之备忘录模式

设计模式系列文章 设计模式(一):创建型之单例模式 设计模式(二、三):创建型之工厂方法和抽象工厂模式 设计模式(四):创建型之原型模式 设计模式(五):创建型之建造者模式 设计模式(六):结构型之代理模式 设计模式…

华为OD机试真题 JavaScript 实现【最短木板长度】【2022Q4 100分】,附详细解题思路

一、题目描述 小明有 n 块木板,第 i ( 1 ≤ i ≤ n ) 块木板长度为 ai。 小明买了一块长度为 m 的木料,这块木料可以切割成任意块,拼接到已有的木板上,用来加长木板。 小明想让最短的木板尽量长。 请问小明加长木板后&#xff0c…

Android12之执行adb disable-verity后android无法启动(一百五十六)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

前沿应用丨大规模无人机集群与“虚实结合”半实物仿真系统

一、应用背景 无人机集群在军事、安全、救援、航空监测、物流配送等领域具有广泛的应用前景。它可以提高任务执行的效率、灵活性和安全性,同时降低人力资源的需求和风险,无人机集群研究涉及多个学科领域,如机器人学、控制理论、通信技术和人工…

Verilog | 基4 booth乘法器

上接乘法器介绍 原理 跟基2的算法一样,假设A和B是乘数和被乘数,且有: A ( a 2 n 1 a 2 n ) a 2 n − 1 a 2 n − 2 … a 1 a 0 ( a − 1 ) B b 2 n − 1 b 2 n − 2 … b 1 b 0 \begin{align}A&(a_{2n1}a_{2n})a_{2n−1}a_{2n−2}……

【ARIMA-LSTM】合差分自回归移动平均方法-长短期记忆神经网络研究(Python代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

基于Nginx1.22+PHP8+MySQL8安装Discuz! X3.5

基于Nginx1.22PHP8MySQL8安装Discuz! X3.5 1. 安装PHP82. 安装MySQL83. 配置Nginx1.224. 安装Discuz! X3.5 1. 安装PHP8 更新系统: yum update安装EPEL存储库: yum install epel-release安装Remi存储库(提供了最新的 PHP 版本)&…

阿里云主机详解:ECS/轻量/虚拟主机/GPU/裸金属/云电脑详解

阿里云云主机分为云虚拟主机、云服务器ECS、轻量应用服务器、GPU云服务器、弹性裸金属服务器、专有宿主机、FPGA云服务器、高性能计算E-HPC、无影云电脑等,阿里云百科来详细说下阿里云云主机详解: 目录 阿里云云主机 云服务器ECS 轻量应用服务器 云…

python数字猜谜2.0

改进了一下数字猜谜: 开头,可选等级: import random guess -1 c 0 print("数字猜谜游戏!") n input("选择等级 A B C:") if (n "A") or (n "a"):guess random.randint…

学习css样式的第二章

1.CSS 布局 - display 属性 display 属性是用于控制布局的最重要的 CSS 属性。 display 属性 display 属性规定是否/如何显示元素。 每个 HTML 元素都有一个默认的 display 值,具体取决于它的元素类型。大多数元素的默认 display 值为 block 或 inline 块级元素…

JavaEE课程设计——校园招聘管理系统(vue框架分析)

目录 Vue架构 登录 Vue架构 前端执行命令 npm run serve 这是整个前端的目录结构 vue.config.js是对前端vue的一个配置, // var webpack require(webpack); const path require(path)function resolve(dir) {return path.join(__dirname, dir) }function pu…

centos下的Nginx的安装

1.Nginx简介 Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。其特点是占有内存少,并发能力强。 其他服务器介绍:Apache服务器、Tomcat服务器、Lighttpd服务器 2.nginx依赖安装 yum -y instal…

【数据分享】1929-2022年全球站点的逐月平均海平面压力数据(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、能见度等指标,说到气象数据,最详细的气象数据是具体到气象监测站点的数据! 对于具体到监测站点的气象数据,之前我们分享过1929-2022年全球气象…

Opencv-C++笔记 (9) : opencv-多通道分离和合并

文章目录 一、概论二、多通道分离函数split()三、多通道合并函数merge()四、图像多通道分离与合并例程 一、概论 在图像颜色模型中不同的分量存放在不同的通道中,如果我们只需要颜色模型的某一个分量,例如只需要处理RGB图像中的红色通道,可以…

数据结构与算法之堆排序

目录 堆排序概述代码实现时间复杂度堆排序概述 堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。…

基于SSM的电影院购票系统开源啦

大家好,今天给大家带来一款SSM的电影院售票系统,非常不错的一个项目,学习javaweb编程必备。 下载地址在文末 1.SpringMVC Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow 里面。Spring 框架提供了构建 Web …

香橙派4 2. 驱动usb2.0芯片cy7c68013

0. 环境 - 香橙派4(Orangepi4_2.1.2_ubuntu_bionic_desktop_linux4.4.179.img) - EZ-USB FX2LP CY7C68013A USB 核心板 1. 下载FX3_SDK_1.3.4_linux EZ-USB™ FX3 Software Development Kit https://www.infineon.com/cms/en/design-support/tools/sdk…