C# Socket网络编程精华篇

我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念:

  1. TCP/IP层次模型

    当然这里我们只讨论重要的四层

       01,应用层(Application):应用层是个很广泛的概念,有一些基本相同的系统级TCP/IP应用以及应用协议,也有许多的企业应用和互联网应用。http协议在应用层运行。

       02,传输层(Tanspot):传输层包括UDP和TCP,UDP几乎不对报文进行检查,而TCP

提供传输保证。

      03,网络层(Netwok):网络层协议由一系列协议组成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

      04,链路层(Link):又称为物理数据网络接口层,负责报文传输。

   然后我们来看下tcp层次模型图

 

     从上图中可以看出,应用程序在应用层运行,在传输层,在数据前加上了TCP头,在

网络层加上的IP头,在数据链路层加上了帧。

   2,端口

    端口号范围:0-65535,总共能表示65536个数。

   按端口号可分为3大类

  (1)公认端口(WellKnownPorts):从0到1023,它们紧密绑定(binding)于一些服务。通常这些端口的通讯明确表明了某种服务的协议。例如:80端口实际上总是HTTP通讯。

  (2)注册端口(RegisteredPorts):从1024到49151。它们松散地绑定于一些服务。也就是说有许多服务绑定于这些端口,这些端口同样用于许多其它目的。例如:许多系统处理动态端口从1024左右开始。

  (3)动态和/或私有端口(Dynamicand/orPrivatePorts):从49152到65535。理论上,不应为服务分配这些端口。实际上,机器通常从1024起分配动态端口。

3.TCP和UDP报文

  下面一起来看下TCP和UDP的报文图

 

      从图中我们可以看出TCP和UDP中都有校验和,但是在UDP报文中,一般不使用校验和,这样可以加快数据传输的速度,但是数据的准确性可能会受到影响。换句话说,Tcp协议都有校验和,为了保证传输数据的准确性。

3.Socket

     Socket包括Ip地址和端口号两部分,程序通过Socket来通信,Socket相当于操作系统的一个组件。Socket作为进程之间通信机制,通常也称作”套接字”,用于描述IP地址和端口号,是一个通信链的句柄。说白了,就是两个程序通信用的。

生活案例对比:

      Socket之间的通信可以类比生活中打电话的案例。任何用户在通话之前,首先要占有一部电话机,相当于申请一个Socket,同时要知道对方的号码,相当于对方有一个固定的Socket,然后向对方拨号呼叫,相当于发出连接请求。假如对方在场并空闲,拿起 电话话筒,双方就可以进行通话了。双方的通话过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机,相当于关闭socket,撤销连接。

     注意:Socket不仅可以在两台电脑之间通信,还可以在同一台电脑上的两个程序间通信。

4,端口进阶(深入)

    通过IP地址确定了网络中的一台电脑后,该电脑上可能提供很多提供服务的应用,每一个应用都对应一个端口。

在Internet上有很多这样的主机,这些主机一般运行了多个服务软件 ,同时提供几种服务,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)

    例如:http 使用80端口,   ftp使用21端口     smtp使用25端口

5.Socket分类

     Socket主要有两种类型:

  1. 流式Socket

          是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低

     2,数据报式Socket

          是一种无连接的Socket,对应于无连接的UDP服务应用,不安全,但效率高

 6. Socket一般应用模式(服务器端和客户端)

     服务器端的Socket(至少需要两个)

        01.一个负责接收客户端连接请求(但不负责与客户端通信)

       02.每成功接收到客户端的连接便在服务器端产生一个对应的复杂通信的Socket

          021.在接收到客户端连接时创建

         022. 为每个连接成功的客户端请求在服务器端都创建一个对应的Socket(负责和客户端通信)

    客户端的Socket

  1. 必须指定要连接的服务器地址和端口
  2. 通过创建一个Socket对象来初始化一个到服务器端的TCP连接

 

      通过上图,我们可以看出,首先服务器会创建一个负责监听的socket,然后客户端通过socket连接到服务器指定端口,最后服务器端负责监听的socket,监听到客户端有连接过来了,就创建一个负责和客户端通信的socket。

下面我们来看下Socket更具体的通信过程:

Socket的通讯过程

  服务器端:

    01,申请一个socket

    02,绑定到一个IP地址和一个端口上

    03,开启侦听,等待接收连接

  客户端:

    01,申请一个socket

   02,连接服务器(指明IP地址和端口号)

   服务器端接收到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通信,原监听socket继续监听。

  注意:负责通信的Socket不能无限创建,创建的数量和操作系统有关。

 7.Socket的构造函数

    Public Socket(AddressFamily addressFamily,SocketType  socketType,ProtocolType  protocolTYpe)

    AddressFamily:指定Socket用来解析地址的寻址方案。例如:InterNetWork指示当Socket使用一个IP版本4地址连接

   SocketType:定义要打开的Socket的类型

   Socket类使用ProtocolType枚举向Windows  Sockets  API通知所请求的协议

注意:

   1,端口号必须在 1 和 65535之间,最好在1024以后。

   2,要连接的远程主机必须正在监听指定端口,也就是说你无法随意连接远程主机。

如:

IPAddress addr = IPAddress.Parse("127.0.0.1");

IPEndPoint endp = new IPEndPoint(addr,,9000);

         服务端先绑定:serverWelcomeSocket.Bind(endp)

         客户端再连接:clientSocket.Connect(endp)

   3,一个Socket一次只能连接一台主机

   4,Socket关闭后无法再次使用

  5,每个Socket对象只能与一台远程主机连接。如果你想连接到多台远程主机,你必须创建多个Socket对象。

8.Socket常用类和方法

  相关类:

   IPAddress:包含了一个IP地址

   IPEndPoint:包含了一对IP地址和端口号

 方法:

   Socket():创建一个Socket

   Bind():绑定一个本地的IP和端口号(IPEndPoint)

   Listen():让Socket侦听传入的连接吃那个病,并指定侦听队列容量

   Connect():初始化与另一个Socket的连接

   Accept():接收连接并返回一个新的Socket

   Send():输出数据到Socket

   Receive():从Socket中读取数据

   Close():关闭Socket,销毁连接

  接下来,我们同一个简单的服务器和客户端通信的案例,来看下Sokcet的具体用法,效果图如下:

 

关键代码:

服务器端代码:

复制代码
  1 private void Form1_Load(object sender, EventArgs e)2 3         {4 5             Control.CheckForIllegalCrossThreadCalls = false;6 7         }8 9  10 11         private void btnListen_Click(object sender, EventArgs e)12 13         {14 15             //ip地址16 17             IPAddress ip = IPAddress.Parse(txtIP.Text);18 19            // IPAddress ip = IPAddress.Any;20 21             //端口号22 23             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));24 25             //创建监听用的Socket26 27             /*28 29              * AddressFamily.InterNetWork:使用 IP4地址。30 31 SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。32 33 ProtocolType.Tcp:使用传输控制协议。34 35              */36 37             //使用IPv4地址,流式socket方式,tcp协议传递数据38 39             Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);40 41             //创建好socket后,必须告诉socket绑定的IP地址和端口号。42 43             //让socket监听point44 45             try46 47             {48 49                 //socket监听哪个端口50 51                 socket.Bind(point);52 53                 //同一个时间点过来10个客户端,排队54 55                 socket.Listen(10);56 57                 ShowMsg("服务器开始监听");58 59                 Thread thread = new Thread(AcceptInfo);60 61                 thread.IsBackground = true;62 63                 thread.Start(socket);64 65             }66 67             catch (Exception ex)68 69             {70 71                72 73                ShowMsg(ex.Message);74 75             }76 77         }78 79         //记录通信用的Socket80 81         Dictionary<string,Socket> dic=new Dictionary<string, Socket>();82 83        // private Socket client;84 85         void AcceptInfo(object o)86 87         {88 89             Socket socket = o as Socket;90 91             while (true)92 93             {94 95                 //通信用socket96 97                 try98 99                 {
100 
101                     //创建通信用的Socket
102 
103                   Socket  tSocket = socket.Accept();
104 
105                   string point = tSocket.RemoteEndPoint.ToString();
106 
107                     //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;
108 
109                     //string me = Dns.GetHostName();//得到本机名称
110 
111                     //MessageBox.Show(me);
112 
113                  ShowMsg(point + "连接成功!");
114 
115                  cboIpPort.Items.Add(point);
116 
117                  dic.Add(point, tSocket);
118 
119                     //接收消息
120 
121                     Thread th = new Thread(ReceiveMsg);
122 
123                     th.IsBackground = true;
124 
125                     th.Start(tSocket);
126 
127                 }
128 
129                 catch (Exception ex)
130 
131                 {
132 
133                     ShowMsg(ex.Message);
134 
135                     break;
136 
137                 }
138 
139             }
140 
141         }
142 
143         //接收消息
144 
145         void ReceiveMsg(object o)
146 
147         {
148 
149             Socket client = o as Socket;
150 
151             while (true)
152 
153             {
154 
155                 //接收客户端发送过来的数据
156 
157                 try
158 
159                 {
160 
161                     //定义byte数组存放从客户端接收过来的数据
162 
163                     byte[] buffer = new byte[1024 * 1024];
164 
165                     //将接收过来的数据放到buffer中,并返回实际接受数据的长度
166 
167                     int n = client.Receive(buffer);
168 
169                     //将字节转换成字符串
170 
171                     string words = Encoding.UTF8.GetString(buffer, 0, n);
172 
173                   
174 
175                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);
176 
177                 }
178 
179                 catch (Exception ex)
180 
181                 {
182 
183                    ShowMsg(ex.Message);
184 
185                     break;
186 
187                 }
188 
189             }
190 
191         }
192 
193  
194 
195         void ShowMsg(string msg)
196 
197         {
198 
199             txtLog.AppendText(msg+"\r\n");
200 
201         }
202 
203  
204 
205         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
206 
207         {
208 
209             //主窗体关闭时关闭子线程
210 
211           
212 
213         }
214 
215         //给客户端发送消息
216 
217         private void btnSend_Click(object sender, EventArgs e)
218 
219         {
220 
221             try
222 
223             {
224 
225                 ShowMsg(txtMsg.Text);
226 
227                 string ip = cboIpPort.Text;
228 
229                 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
230 
231                 dic[ip].Send(buffer);
232 
233                 // client.Send(buffer);
234 
235             }
236 
237             catch (Exception ex)
238 
239             {
240 
241                ShowMsg(ex.Message);
242 
243             }
244 
245  
246 
247         }
复制代码

 

客户端代码:

复制代码
  1 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);2 3         private void btnConnection_Click(object sender, EventArgs e)4 5         {6 7             //连接到的目标IP8 9             IPAddress ip = IPAddress.Parse(txtIP.Text);10 11             //IPAddress ip = IPAddress.Any;12 13             //连接到目标IP的哪个应用(端口号!)14 15             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));16 17             try18 19             {20 21                 //连接到服务器22 23                 client.Connect(point);24 25                 ShowMsg("连接成功");26 27                 ShowMsg("服务器" + client.RemoteEndPoint.ToString());28 29                 ShowMsg("客户端:" + client.LocalEndPoint.ToString());30 31                 //连接成功后,就可以接收服务器发送的信息了32 33                 Thread th=new Thread(ReceiveMsg);34 35                 th.IsBackground = true;36 37                 th.Start();38 39             }40 41             catch (Exception ex)42 43             {44 45                 ShowMsg(ex.Message);46 47             }48 49         }50 51         //接收服务器的消息52 53         void ReceiveMsg()54 55         {56 57             while (true)58 59             {60 61                 try62 63                 {64 65                     byte[] buffer = new byte[1024 * 1024];66 67                     int n = client.Receive(buffer);68 69                     string s = Encoding.UTF8.GetString(buffer, 0, n);70 71                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);72 73                 }74 75                 catch (Exception ex)76 77                 {78 79                     ShowMsg(ex.Message);80 81                     break;82 83                 }84 85             }86 87           88 89         }90 91  92 93         void ShowMsg(string msg)94 95         {96 97             txtInfo.AppendText(msg+"\r\n");98 99         }
100 
101  
102 
103         private void btnSend_Click(object sender, EventArgs e)
104 
105         {
106 
107             //客户端给服务器发消息
108 
109             if (client!=null)
110 
111             {
112 
113                 try
114 
115                 {
116 
117                    ShowMsg(txtMsg.Text);
118 
119                     byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
120 
121                     client.Send(buffer);
122 
123                 }
124 
125                 catch (Exception ex)
126 
127                 {
128 
129                    ShowMsg(ex.Message);
130 
131                 }
132 
133             }
134 
135            
136 
137         }
138 
139  
140 
141         private void ClientForm_Load(object sender, EventArgs e)
142 
143         {
144 
145             Control.CheckForIllegalCrossThreadCalls = false;
146 
147         }
复制代码

转载于:https://www.cnblogs.com/asdyzh/p/9839775.html

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript --- [虚拟DOM] 初始化 实现

说明 本篇主要说明为什么要使用虚拟DOM技术,以及如何实现简单的虚拟dom您将会学到: 1.原生JS对DOM的操作 2.虚拟DOM的相关概念 3.DIFF算法的基础概念 为什么提出 -> DOM操作慢 我们使用createElement属性来创建一个最常见的div,看看一个最常见的DOM有多少个属性 <scri…

模块单元学习笔记(日志记录模块os模块sys)

一、日志记录模块 Logging 默认情况下&#xff0c;logging将日志打印到屏幕&#xff0c;日志级别大小关系为&#xff1a;CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET&#xff0c;当然也可以自己定义日志级别。 DEBUG&#xff1a;详细的信息,通常只出现…

tomcat8 进入不了Manager App 界面 403 Access Denied

准备 1.注释掉context.xml中的value属性 使用下面的命令&#xff1a; vim /usr/local/tomcats/tomcat-daily/webapps/manager/META-INF/context.xml 注释掉其中value节点 2.修改tomcat-users.xml文件 加入下面的配置 <role rolename"manager-gui" /><role …

MySQL中varchar最大长度是多少

一. varchar存储规则&#xff1a; 4.0版本以下&#xff0c;varchar(20)&#xff0c;指的是20字节&#xff0c;如果存放UTF8汉字时&#xff0c;只能存6个&#xff08;每个汉字3字节&#xff09; 5.0版本以上&#xff0c;varchar(20)&#xff0c;指的是20字符&#xff0c;无论存放…

salesforce lightning零基础学习(三) 表达式的!(绑定表达式)与 #(非绑定表达式)

在salesforce的classic中&#xff0c;我们使用{!expresion}在前台页面展示信息&#xff0c;在lightning中&#xff0c;上一篇我们也提及了&#xff0c;如果展示attribute的值&#xff0c;可以使用{!v.expresion}展示信息。 lightning在component中解析动态值的时候&#xff0c;…

网络协议各层概述

网络协议概述 OSI是一个开放性的通信系统互连参考模型&#xff0c;他是一个定义得非常好的协议规范。OSI模型有7层结构&#xff0c;每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层&#xff1b; 其中高层&…

javascript --- 实现对象的深拷贝

浅拷贝和深拷贝 浅拷贝: 只拷贝一层.当对象是复杂数据类型(Object、 Array)时,只拷贝引用深拷贝: 多层拷贝.复杂数据类型,会重新分配内存空间. 实现浅拷贝的2种方法 使用for ... in 实现 var obj {name: marron,age: 18,msg: {sex: "1" } } var o {}; for(let …

Qt与FFmpeg联合开发指南(二)——解码(2):封装和界面设计

与解码相关的主要代码在上一篇博客中已经做了介绍&#xff0c;本篇我们会先讨论一下如何控制解码速度再提供一个我个人的封装思路。最后回归到界面设计环节重点看一下如何保证播放器界面在缩放和拖动的过程中保证视频画面的宽高比例。 一、解码速度 播放器播放媒体文件的时候播…

Bzoj1051 受欢迎的牛

每一头牛的愿望就是变成一头最受欢迎的牛。现在有 N 头牛&#xff0c;给你 M 对整数 (A,B)&#xff0c;表示牛 A 认为牛 B 受欢迎。这种关系是具有传递性的&#xff0c;如果 A 认为 B 受欢迎&#xff0c;B 认为 C 受欢迎&#xff0c;那么牛 A 也认为牛 C 受欢迎。你的任务是求出…

javascript --- 文件上传即时预览 闭包实现多图片即时预览

使用javascript原生功能实现,点击上传文件,然后再网页上显示出来 1. 初级显示 1.1 准备一个input标签和一个img标签 <input typefile id"file"> <img id"preview" src"">1.2 js代码如下 // 将上传的图片显示到页面上function sho…

第一次作业:深入Linux源码分析进程模型

一.进程的概念 第一&#xff0c;进程是一个实体。每一个进程都有它自己的地址空间&#xff0c;一般情况下&#xff0c;包括文本区域&#xff08;text region&#xff09;、数据区域&#xff08;data region&#xff09;和堆栈&#xff08;stack region&#xff09;。文本区域存…

关于模型验证那点事儿

今天应笑笑老师之问&#xff0c;做了一个模型验证的例子&#xff0c;发现之前对这个东西的理解太片面&#xff0c;重新整理了一下思路 字段验证优先级高于类验证 什么是类验证呢&#xff1f;就是两个字段组合的验证&#xff0c;比如你Admin不允许修改密码&#xff0c;你修改密码…

Win10安装MySQL5.7.22 解压缩版(手动配置)方法

1.下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html#downloads 直接点击下载项 下载后&#xff1a; 2.可以把解压的内容随便放到一个目录&#xff0c;我的是如下目录&#xff08;放到C盘的话&#xff0c;可能在修改ini文件时涉及权限问题&#xff0c;之后我…

Elemant-UI日期范围的表单验证

Form 组件提供了表单验证的功能&#xff0c;只需要通过 rules 属性传入约定的验证规则&#xff0c;并将 Form-Item 的 prop 属性设置为需校验的字段名即可。但是官网的示例只有普通日期类型的验证&#xff0c;没有时间范围的验证。 一开始&#xff0c;我认为时间时间范围的是一…

node --- [express项目] 开发环境下使用morgan控制台输出访问信息

说明 源代码记录、遗忘回顾 process.env node中提供了一个process.env接口用于访问计算机中的系统环境变量. 可以利用以上属性来区分当前的环境是开发环境还是生产环境,代码如下: if (process.env.NODE_ENV development) {console.log(当前环境是开发环境) } else {consol…

Dynamics CRM 访问团队的使用

访问团队和负责人团队的区别是&#xff1a;负责人团队可以拥有记录&#xff0c;访问团队不能拥有记录也不能加入解决方案中。 访问团队用法1&#xff1a;可以将不同组织的人员加入到访问组实现数据的更新、删除、共享 访问团队用法2&#xff1a;访问团队模板的使用 步骤一&…

node --- [express] cookie/session 机制与 中间件的使用(路由守卫)

说明 源代码记忆、遗忘回顾使用 cookie/session 机制,让 客户端/服务器 的访问变得有状态 cookie 与 session 由于 HTTP 协议的无状态性,当一次连接断开后. 服务器并不会记录用户是否登录. 因此需要引入 cookie/session 机制 cookie cookie: 浏览器在电脑硬盘中开辟的一块空…

02 数据类型

转载于:https://www.cnblogs.com/theoup/p/9875293.html

(数据科学学习手札30)朴素贝叶斯分类器的原理详解Python与R实现

一、简介 要介绍朴素贝叶斯&#xff08;naive bayes&#xff09;分类器&#xff0c;就不得不先介绍贝叶斯决策论的相关理论&#xff1a; 贝叶斯决策论&#xff08;bayesian decision theory&#xff09;是概率框架下实施决策的基本方法。对分类任务来说&#xff0c;在所有相关概…

Shiro身份认证---转

目录1.Shro的概念2.Shiro的简单身份认证实现3.Shiro与spring对身份认证的实现前言&#xff1a; Shiro 可以非常容易的开发出足够好的应用&#xff0c;其不仅可以用在 JavaSE 环境&#xff0c;也可以用在 JavaEE 环境。Shiro 可以帮助我们完成&#xff1a;认证、授权、加密、会话…