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的具体用法,效果图如下:

服务器端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace 服务器
{public partial class FServer : Form{IPAddress ip;IPEndPoint point;public FServer(){InitializeComponent();ServerListen();}private void ServerListen()   {//ip地址 ip = IPAddress.Parse(txtIP.Text);// IPAddress ip = IPAddress.Any;//端口号point = new IPEndPoint(ip, int.Parse(txtPort.Text)); //创建监听用的Socket /*AddressFamily.InterNetWork:使用 IP4地址。SocketType.Stream:支持可靠、双向、基于连接的字节流,而不重复数据。此类型的 Socket 与单个对方主机进行通信,并且在通信开始之前需要远程主机连接。Stream 使用传输控制协议 (Tcp) ProtocolType 和 InterNetworkAddressFamily。 ProtocolType.Tcp:使用传输控制协议。  */  //使用IPv4地址,流式socket方式,tcp协议传递数据  Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //创建好socket后,必须告诉socket绑定的IP地址和端口号。 //让socket监听point  try{  //socket监听哪个端口 socket.Bind(point);  //同一个时间点过来60个客户端,排队 socket.Listen(60);  ShowMsg("服务器开始监听"); Thread thread = new Thread(AcceptInfo);  thread.IsBackground = true;  thread.Start(socket);  }  catch (Exception ex)  {ShowMsg(ex.Message);  }  }//记录通信用的Socket  Dictionary<string, Socket> dic = new Dictionary<string, Socket>();  // private Socket client; void AcceptInfo(object o){  Socket socket = o as Socket;  while (true) {  //通信用socket try  { //创建通信用的SocketSocket tSocket = socket.Accept();string point = tSocket.RemoteEndPoint.ToString();//IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;//string me = Dns.GetHostName();//得到本机名称//MessageBox.Show(me);ShowMsg(point + "连接成功!");ComboBoxAddItems(point);dic.Add(point, tSocket);//接收消息Thread th = new Thread(ReceiveMsg);th.IsBackground = true;th.Start(tSocket);}catch (Exception ex){ShowMsg(ex.Message);break; }}}//接收消息 void ReceiveMsg(object o){Socket client = o as Socket;while (true){//接收客户端发送过来的数据try{//定义byte数组存放从客户端接收过来的数据byte[] buffer = new byte[1024 * 1024];//将接收过来的数据放到buffer中,并返回实际接受数据的长度int n = client.Receive(buffer);//将字节转换成字符串string words = Encoding.UTF8.GetString(buffer, 0, n);ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);}catch (Exception ex){if (!client.Connected) ComboBoxRoMoveItems(client.RemoteEndPoint.ToString());ShowMsg(ex.Message); break;}}}delegate void SetTextCallback(string msg);public void ShowMsg(string msg){if (this.txtLog.InvokeRequired){SetTextCallback d = new SetTextCallback(ShowMsg);this.Invoke(d, new object[] { msg });}else{this.txtLog.AppendText(msg + "\r\n");}}delegate void SetComboBox(String msg);public void ComboBoxAddItems(string msg){if (this.cboIpPort.InvokeRequired){SetTextCallback d = new SetTextCallback(ComboBoxAddItems);this.Invoke(d, new object[] { msg });}else{this.cboIpPort.Items.Add(msg);}}public void ComboBoxRoMoveItems(string msg){if (this.cboIpPort.InvokeRequired){SetTextCallback d = new SetTextCallback(ComboBoxRoMoveItems);this.Invoke(d, new object[] { msg });}else{this.cboIpPort.Items.Remove(msg);cboIpPort.SelectedIndex = -1;}}//给客户端发送消息private void btnSend_Click(object sender, EventArgs e){try{                string ip = cboIpPort.Text;if (cboIpPort.Text.Length > 5){                    byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);dic[ip].Send(buffer);ShowMsg(point.ToString() + ":" + txtMsg.Text);}else{}}catch (Exception ex){ShowMsg(ex.Message);}}private void Clearbtn_Click(object sender, EventArgs e){this.txtLog.Text = "";}}
}

 

客户端代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;namespace 客户端
{public partial class FClient : Form{Socket client;IPAddress ip;IPEndPoint point;bool isExits = false;public FClient(){InitializeComponent();}private void FClient_Load(object sender, EventArgs e){ip = IPAddress.Parse(txtIP.Text);  point = new IPEndPoint(ip, int.Parse(txtPort.Text));Thread serverConnetThread = new Thread(ServerConnetThread);serverConnetThread.IsBackground = true;serverConnetThread.Start();}private void ServerConnet(){try{//连接到服务器  if (client != null) client.Close();client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);client.Connect(point);ShowMsg("连接成功");ShowMsg("服务器:" + client.RemoteEndPoint.ToString());ShowMsg("客户端:" + client.LocalEndPoint.ToString());//连接成功后,就可以接收服务器发送的信息了 Thread th = new Thread(ReceiveMsg);th.IsBackground = true;th.Start();}catch (Exception ex){ShowMsg(ex.Message);}}private void ServerConnetThread()  {while (!isExits){if (client == null || !client.Connected) {ServerConnet();}Thread.Sleep(5000);}           }//接收服务器的消息void ReceiveMsg(){while (true){try {byte[] buffer = new byte[1024 * 1024];int n = client.Receive(buffer);string s = Encoding.UTF8.GetString(buffer, 0, n);ShowMsg(point.ToString() + ":" + s);}catch (Exception ex){ShowMsg(ex.Message);break;}}           }delegate void SetTextCallback(string msg);public void ShowMsg(string msg){if (this.txtInfo.InvokeRequired){SetTextCallback d = new SetTextCallback(ShowMsg);this.Invoke(d, new object[] { msg });}else{this.txtInfo.AppendText(msg + "\r\n");}}private void btnSend_Click(object sender, EventArgs e){//客户端给服务器发消息          if (client != null)                {               try{ShowMsg(client.RemoteEndPoint + ":" + txtMsg.Text);byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);                   client.Send(buffer);                    }               catch (Exception ex){                 ShowMsg(ex.Message);                    }              }}private void Clearbtn_Click(object sender, EventArgs e){this.txtInfo.Text = "";}}
}

 

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

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

相关文章

PHP + NGINX 控制视频文件播放,并防止文件下载

最简单的方法是使用NGINX的 internal 功能 server { listen 80; server_name www.xxx.com;  location / { index index.php index.html index.htm; root /xxx; if (!-e $request_filename) { rewrite ^/index.php(.*)$ /index.php?s$…

C#:委托基础与事件

通过以下思维导图&#xff0c;学习委托的基本概念&#xff0c;后面着重讲解委托的运用&#xff0c;希望通过最简单的方式收获更多的知识。 1.委托的各种写法 1、委托 委托名new 委托&#xff08;会调用的方法名); 委托名&#xff08;参数&#xff09;; 2、委托 委托名 会调用…

Django基本命令

Django基本命令 1.创建一个Django 项目 django_admin.py startproject mysite当前目录下会生成mysite的工程&#xff0c;目录结构如下&#xff1a; manage.py ----- Django项目里面的工具&#xff0c;通过它可以调用django shell和数据库等。settings.py ---- 包含了项目的默认…

reactor模式:多线程的reactor模式

上文说到单线程的reactor模式 reactor模式&#xff1a;单线程的reactor模式 单线程的reactor模式并没有解决IO和CPU处理速度不匹配问题&#xff0c;所以多线程的reactor模式引入线程池的概念&#xff0c;把耗时的IO操作交由线程池处理&#xff0c;处理完了之后再同步到selecti…

Elasticsearch实战篇——Spring Boot整合ElasticSearch

2019独角兽企业重金招聘Python工程师标准>>> 当前Spring Boot很是流行&#xff0c;包括我自己&#xff0c;也是在用Spring Boot集成其他框架进行项目开发&#xff0c;所以这一节&#xff0c;我们一起来探讨Spring Boot整合ElasticSearch的问题。 本文主要讲以下内容…

Python: pip升级报错了:You are using pip version 10.0.1, however version 20.3.3 is available.

1,Python使用命令&#xff1a;python -m pip install --upgrade pip升级pip的时候报了下面这个错 2,换了个命令&#xff1a; python -m pip install --upgrade pip -i https://pypi.douban.com/simple 更新成功了&#xff0c;但又报了一个新的错误&#xff1a; AttributeError:…

新手上路之Hibernate:第一个Hibernate例子

一、Hibernate概述 &#xff08;一&#xff09;什么是Hibernate&#xff1f; Hibernate核心内容是ORM&#xff08;关系对象模型&#xff09;。可以将对象自动的生成数据库中的信息&#xff0c;使得开发更加的面向对象。这样作为程序员就可以使用面向对象的思想来操作数据库&…

模板标签及模板的继承与引用

1.常用的模板标签 - 作用是什么:提供各种逻辑 view.py: def index(request):#模板标签 --常用标签 总结&#xff1a;语法 {% tag %} {% endtag %} {% tag 参数 参数 %} 示例 展示页index.html&#xff0c;包含for标签&#xff0c;if标签&#xff0c;url标签 {% extends teacher…

Golang实现一个密码生成器

小地鼠防止有人偷他的果实&#xff0c;在家里上了一把锁。这个锁怎么来的呢&#xff1f;请往下看。。 package mainimport ("flag""fmt""math/rand""time" )var (length intcharset string )const (NUmStr "0123456789"C…

C# WPF:初识布局容器

StackPanel堆叠布局 StackPanel是简单布局方式之一&#xff0c;可以很方便的进行纵向布局和横向布局 StackPanel默认是纵向布局的 <Window x:Class"WpfApplication1.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" …

Kibana源码分析--Hapijs路由设置理解笔记

【ES6解构赋值】&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment 【Joi APi】&#xff1a;https://github.com/hapijs/joi/blob/v13.1.2/API.md 转载于:https://www.cnblogs.com/lishidefengchen/p/866874…

Python打包EXE神器 pyinstaller

最近由于项目需要&#xff0c;以前的python文件需要编辑为EXE供前端客户使用。 由于最早接触的是distutils&#xff0c;所以一开始准备使用distutils和py2exe搭配来进行python的exe化&#xff0c;也就是传统的使用setup.py的方式来进行exe安装。但是结果都不是很好&#xff0c;…

20种PLC元件编号和Modbus编号地址对应表

1、三菱&#xff1a; X元件支持Modbus之02功能码&#xff1b; Y元件支持Modbus之01、05、15功能码&#xff1b; D元件支持Modbus之03、06、16功能码。 2、西门子&#xff1a; I元件支持Modbus之02功能码&#xff1b; Q元件支持Modbus之01、05、15功能码&#xff1b; V元件…

暑期学习

由于最后大作业的呈现情况与短学期所完成的还相差甚远&#xff0c;所以在暑期的时候开始进一步的细化。 在这个过程之中产生了如下的问题&#xff1a; 已解决的有&#xff1a; 1.用a标签在同一页面实现跳转。 要点&#xff1a;标记<a href"../home#pre">的时候…

五、RabbitMQ的消息属性(读书笔记)

2019独角兽企业重金招聘Python工程师标准>>> 简介 当使用RabbitMQ发布消息时&#xff0c;消息又AMQP规范中的三个低层帧类型组成&#xff1a; Basic.publish方法帧&#xff1b;内容头帧&#xff1b;消息体帧&#xff1b;这三种帧类型按顺序一起工作&#xff0c;以便…

异步和单线程

转载于:https://www.cnblogs.com/sunmarvell/p/8674748.html

C#:把dll封入exe中方法

在这个事件中,可以重新为加载失败的程序集手动加载 如果你将dll作为资源文件打包的你的应用程序中(或者类库中) 就可以在硬盘加载失败的时候 从资源文件中加载对应的dll 就像这样: class Program {static Program(){ //这个绑定事件必须要在引用到TestLibrary1这个程序…

C#结构类型图

转载于:https://www.cnblogs.com/kangao/p/8674838.html

使用gradle多渠道打包

以友盟的多渠道打包为例&#xff0c;如果我们须要打包出例如以下渠道&#xff1a;UMENG, WANDOUJIA, YINGYONGBAO。 第一种方法。是须要创建文件的。我们在写完我们的代码之后&#xff0c;在app/src以下。分别创建和main同级目录的目录umeng, wandoujia, yingyongbao,这三个目录…

四大步骤,彻底关闭Win10自动更新

尽管Win11已经发布了一段时间&#xff0c;但目前互联网上大部分电脑用户所使用的的操作系统仍是Win10&#xff0c;对于Win10&#xff0c;笔者相信大部分人应该都不陌生&#xff0c;作为目前市面上占比最高的电脑系统&#xff0c;Win10的许多功能和操作逻辑都十分优秀&#xff0…