C#上位机之网口通信与协议!

文章目录

  • 前言
  • 一、网口通信概念
  • 二、使用网口通信准备
  • 三、使用步骤


前言

C#上位机之网口通信与协议!


一、网口通信概念

定义 :Socket 可以理解为一个通信端点,它提供了应用程序与网络之间的接口,使得应用程序能够在网络上发送和接收数据。通过 Socket,不同设备上的应用程序可以建立连接,实现数据的交换。
地址族 :用于确定 Socket 能够使用的协议类型,常见的有 AF_INET(IPv4 地址族)、AF_INET6(IPv6 地址族)、AF_UNIX(本地通信的 UNIX 域协议)等。
类型
流式套接字(SOCK_STREAM) :提供面向连接的、可靠的、双向的字节流服务,基于 TCP 协议。数据传输保证顺序、完整且无重复,适用于对数据可靠性要求较高的场景,如文件传输、远程登录等。
数据报套接字(SOCK_DGRAM) :提供无连接的、不可靠的、基于数据报的包传输服务,基于 UDP 协议。数据报独立传输,可能存在丢失、重复或乱序的情况,但传输效率较高,适用于对实时性要求较高、少量丢包可以接受的场景,如视频直播、在线游戏等。
原始套接字(SOCK_RAW) :允许对低层协议进行访问和操作,可直接处理 IP 数据报或更低层协议的数据,通常用于网络工具开发、协议研究等特殊场景。

二、使用网口通信准备

1、下载网络调试助手软件
在这里插入图片描述
2、Socket概念
地址族(AddressFamily):如 InterNetwork (IPv4)、InterNetworkV6 (IPv6)。
套接字类型(SocketType):如 Stream (TCP)、Dgram (UDP)。
协议类型(ProtocolType):如 Tcp 、Udp 。
IPEndPoint:表示网络终结点(IP 地址 + 端口)。
3、Socket工作流程

阶段服务器端操作客户端操作
创建套接字(Socket)创建一个 Socket 对象,指定地址族、套接字类型和协议类型。创建一个 Socket 对象,指定地址族、套接字类型和协议类型。
绑定地址(Bind)使用 Bind 方法将套接字绑定到本地的 IP 地址和端口号。通常不需要显式绑定,除非需要指定本地地址和端口。
监听连接(Listen)调用 Listen 方法开始监听来自客户端的连接请求,进入监听状态,等待客户端连接。(仅TCP)无此操作。
建立连接(Accept)调用 Accept 方法接受客户端的连接请求,建立与客户端之间的连接,返回一个新的套接字用于与客户端通信(仅TCP)。调用 Connect 方法向服务器端发起连接请求,尝试与服务器端建立连接。
数据传输通过返回的套接字使用 Receive 方法接收客户端发送的数据,使用 Send 方法向客户端发送数据。通过套接字使用 Send 方法向服务器端发送数据,使用 Receive 方法接收服务器端发送的数据。
关闭连接(Close)数据传输完成后,调用 Shutdown 方法关闭套接字的发送和接收功能,然后调用 Close 方法释放套接字资源,关闭连接。数据传输完成后,调用 Shutdown 方法关闭套接字的发送和接收功能,然后调用 Close 方法释放套接字资源,关闭连接。

三、使用步骤

TCP服务器
C#创建socket服务端,但这种方法只能接收一个客户端连接和处理一次接收到的信息。解释:当启动服务端后程序会停在Socket socketClient = socketServer.Accept();处等待客户端连接,当有客户端来连接程序就会停在int bytesReader = socketClient.Receive(recvData);等待客户端发送消息。

// 1、创建Socket
Socket socketServer = new Socket(AddressFamily.InterNetwork,// 地址族IPv4SocketType.Stream, // 套接字类型ProtocolType.Tcp// TCP协议);
// 2、绑定IP和端口
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
socketServer.Bind(endPoint);// 3、开始监听
socketServer.Listen();
Debug.WriteLine($"服务器已启动,等待连接");// 4、接收客户端连接
Socket socketClient = socketServer.Accept();
Debug.WriteLine($"连接的客户端:{socketClient.RemoteEndPoint}");// 5、接收数据
byte[] recvData = new byte[1024];
int bytesReader = socketClient.Receive(recvData);// 返回接收到的字节数
Debug.WriteLine($"收到的消息:{Encoding.UTF8.GetString(recvData,0, bytesReader)}");// 6、发送响应
byte[] sendMes = Encoding.UTF8.GetBytes("Hello I am Server");
socketClient.Send(sendMes);// 7、关闭连接
//socketClient.Close();
//socketServer.Close();

如果需要连接多个客户端和接收信息,可以使用While循环来实现

// 1、创建Socket
Socket socketServer = new Socket(AddressFamily.InterNetwork,// 地址族IPv4SocketType.Stream, // 套接字类型ProtocolType.Tcp// TCP协议);
// 2、绑定IP和端口
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
socketServer.Bind(endPoint);// 3、开始监听
socketServer.Listen();
Debug.WriteLine($"服务器已启动,等待连接");
while (true)
{// 4、接收客户端连接Socket socketClient = socketServer.Accept();Debug.WriteLine($"连接的客户端:{socketClient.RemoteEndPoint}");while (true){// 5、接收数据byte[] recvData = new byte[1024];int bytesReader = socketClient.Receive(recvData);// 返回接收到的字节数Debug.WriteLine($"收到的消息:{Encoding.UTF8.GetString(recvData, 0, bytesReader)}");// 6、发送响应byte[] sendMes = Encoding.UTF8.GetBytes("Hello I am Server");socketClient.Send(sendMes);}
}

但是使用上述方法程序在

while (true)
{// 5、接收数据byte[] recvData = new byte[1024];int bytesReader = socketClient.Receive(recvData);// 返回接收到的字节数Debug.WriteLine($"收到的消息:{Encoding.UTF8.GetString(recvData, 0, bytesReader)}");// 6、发送响应byte[] sendMes = Encoding.UTF8.GetBytes("Hello I am Server");socketClient.Send(sendMes);
}

这段代码处陷入死循环,只能重复接收一个客户端的消息。
如何解决上述的问题呢?
可以使用Task线程来解决。相当于每来一个客户端就创建一个线程来处理这个客户端发送的数据。

// 1、创建Socket
Socket socketServer = new Socket(AddressFamily.InterNetwork,// 地址族IPv4SocketType.Stream, // 套接字类型ProtocolType.Tcp// TCP协议);
// 2、绑定IP和端口
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
socketServer.Bind(endPoint);// 3、开始监听
socketServer.Listen();
Debug.WriteLine($"服务器已启动,等待连接");
while (true)
{// 4、接收客户端连接Socket socketClient = socketServer.Accept();Debug.WriteLine($"连接的客户端:{socketClient.RemoteEndPoint}");Task.Factory.StartNew(() =>{while (true){// 5、接收数据byte[] recvData = new byte[1024];int bytesReader = socketClient.Receive(recvData);// 返回接收到的字节数Debug.WriteLine($"收到的消息:{Encoding.UTF8.GetString(recvData, 0, bytesReader)}");// 6、发送响应byte[] sendMes = Encoding.UTF8.GetBytes("Hello I am Server");socketClient.Send(sendMes);}});
}
// 7、关闭连接
//socketClient.Close();
//socketServer.Close();

部分代码解读:

Task.Factory.StartNew 创建一个线程并开启这个线程。

TCP客户端

//  1、创建Socket
Socket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 2、连接服务器
IPEndPoint serverPoin = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
socketClient.Connect(serverPoin);
Debug.WriteLine($"已连接到服务器");// 3、发送数据
byte[] senfMsg = Encoding.UTF8.GetBytes("I am Client");
socketClient.Send(senfMsg);// 4、接收响应
byte[] recvMsg = new byte[1024];
int bytesReader = socketClient.Receive(recvMsg);
string response = Encoding.UTF8.GetString(recvMsg, 0,bytesReader);
Debug.WriteLine($"接收到的消息:{response}");// 5、关闭连接
//socketClient.Close();

UDP通信

// 1、创建UDP
Socket udp = new Socket(AddressFamily.InterNetwork,SocketType.Dgram,ProtocolType.Udp);
// 2.绑定端口
udp.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888));// 1、指定地址
EndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9999);
// 2、给指定地址发送信息
udp.SendTo(Encoding.UTF8.GetBytes("Hello UDP"),endPoint);// 接收信息的字节数组
byte[] buffer = new byte[1024];
// IPAddress.Any 服务器会接受来自任何网络接口的连接请求,表示端口号由操作系统自动分配
endPoint = new IPEndPoint(IPAddress.Any, 0);
// 参数ref endPoint指定接收数据的来源
int bytesReader = udp.ReceiveFrom(buffer,ref endPoint);
string message = Encoding.UTF8.GetString(buffer, 0, bytesReader);
Debug.WriteLine(message);// 2、广播模式
udp.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
endPoint = new IPEndPoint(IPAddress.Parse("255.255.255.255"), 9999);
udp.SendTo(Encoding.UTF8.GetBytes("Hello UDP!-BroadCast"), endPoint);

TcpClient,简化了 TCP 协议的通信流程。

构造方法说明
TcpClient()初始化一个新的 TcpClient 实例,不指定远程主机和端口。
TcpClient(string hostname, int port)初始化一个新的 TcpClient 实例,并连接到指定的远程主机和端口。
属性说明使用方法示例
Client获取底层的 Socket 对象,用于更细粒度的网络操作。Socket socket = tcpClient.Client;
Connected获取一个布尔值,指示 TcpClient 是否连接到远程主机。if (tcpClient.Connected) { ... }
Available获取接收缓冲区中等待接收的字节数。int availableBytes = tcpClient.Available;
ReceiveBufferSize获取或设置接收缓冲区的大小。int bufferSize = tcpClient.ReceiveBufferSize;tcpClient.ReceiveBufferSize = 1024;
SendBufferSize获取或设置发送缓冲区的大小。int bufferSize = tcpClient.SendBufferSize;tcpClient.SendBufferSize = 1024;
方法说明使用方法示例
Connect(string host, int port)连接到远程 TCP 服务器的指定主机和端口。tcpClient.Connect("127.0.0.1", 8888);
GetStream()返回一个 NetworkStream 对象,用于在 TcpClient 上进行读写操作。NetworkStream stream = tcpClient.GetStream();
Close()关闭 TcpClient 和其底层的 SockettcpClient.Close();
Dispose()释放 TcpClient 使用的资源。tcpClient.Dispose();

TCP客户端

// 1、创建TcpClient
using ( TcpClient client = new TcpClient())
{client.Connect("127.0.0.1",8888);Debug.WriteLine("已连接到服务器");// 2、获取网络流NetworkStream stream = client.GetStream();// 3、发送数据string message = "Hello Server!";byte[] sentBytes = Encoding.UTF8.GetBytes(message);stream.Write(sentBytes, 0, sentBytes.Length);Debug.WriteLine($"发送:{message}");// 4、接收响应byte[] buffer = new byte[1024];int bytesRead = stream.Read(buffer, 0, buffer.Length);string response = Encoding.UTF8.GetString(buffer);Debug.WriteLine(response);

TCP服务端

// 监听指定IP和端口
TcpListener server = new TcpListener(IPAddress.Any, 8888);
server.Start();
Debug.WriteLine($"服务器已启动,等待连接.....");try
{// 接收客户端连接using (TcpClient client = server.AcceptTcpClient()){Debug.WriteLine($"客户端已连接:{((IPEndPoint)client.Client.RemoteEndPoint).Address}");// 2、获取网络流NetworkStream stream = client.GetStream();// 3、接收数据byte[] buffer = new byte[1024];int bytesRead = stream.Read(buffer, 0, buffer.Length);string message = Encoding.UTF8.GetString(buffer, 0, bytesRead);Debug.WriteLine(message);// 4、发送响应string response = "Hello Client!";byte[] sendData = Encoding.UTF8.GetBytes(response);stream.Write(sendData, 0, sendData.Length);}
}catch(Exception ex)
{Debug.WriteLine($"错误:{ex.Message}");
}
finally
{server.Stop();
}

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

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

相关文章

Android Studio 创建类时如何自动添加类注释

打开IDEA或AS,点击菜单栏File——Settings——Editor——File and Code Templates。 点击右边Tab页的Includes,选择File Header,修改类头模版,如图: 记得选中Project,否则默认是整个AS都会进行设置

C++11:shared_ptr的设计哲学(原理+源码):内存安全和性能的架构权衡

0.简介 在C编程世界中,内存管理是一把双刃剑,手动管理带来了极致的内存控制能力,但也带来了像内存泄漏,野指针等问题;自动垃圾回收虽然安全,但却会带来一定的性能损耗。本文将介绍C11引入shared_ptr&#…

Mysql EXPLAIN 执行计划

EXPLAIN SELECT SQl。。。。界面filtered储引擎返回的数据在经过服务器层 WHERE 条件过滤后,剩余数据占总行数的百分比估计值rows * filtered/100 越接近100%效率越高rowspossible_keys 可能选择的索引key最终决定选择的行partitions问了哪些分区select_type查询…

力扣刷题记录【1】146.LRU缓存

前言: 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类: LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值&…

西门子S7-1200 PLC主流通信方法及应用

一、通信基础 1. 网络术语与设备 - 关键设备:交换机、路由器、网关等。 - 物理接口:RS-485(支持多点通信)、RS-232C(点对点串行通信)。 2. OSI参考模型 - 核心框架:理解协议分层&…

MySQL实现任意级子目录的主要方案以及区别

常见的实现方案及区别 1. 邻接表(Adjacency List) 方案描述: 每条记录存储一个节点的父节点ID。 表结构大致: id INT PRIMARY KEY, name VARCHAR(...), parent_id INT -- 指向父节点的ID,根节点为NULL或0优点&…

Linux网络socket套接字(完)(5)

文章目录前言一、多进程版的Tcp网络程序捕捉SIGCHLD信号让孙子进程提供服务二、多线程版的Tcp网络程序三、线程池版的Tcp网络程序四、Tcp协议通讯流程通讯流程总览三次握手的过程数据传输的过程四次挥手的过程总结前言 结束喽,至少这个Tcp套接字有关内容要结束了~  …

Web3 Study Log 003

Web3 Study Log 003 2025-7-5 这几天各种各样的琐事,处理完了,真的烦,估计能消停一段时间了… 今天终于能够坐下来好好学习,今天学习了chainlink的使用,能够获取 ETH/USD 实时价格,然后写了一个简单的众…

Kotlin:2.1.20 的新特性

一、概述 The Kotlin 2.1.20 release is here! Here are the main highlights: Kotlin 2.1.20发布了,主要亮点如下: K2 compiler updates: updates to the new kapt and Lombok pluginsKotlin Multiplatform: new DSL to replace Gradle’s Application …

设计模式 | 观察者模式

观察者模式(Observer Pattern)是行为型设计模式中的事件通知专家,它定义了对象间一种一对多的依赖关系,当一个对象状态改变时,所有依赖它的对象都会自动收到通知并更新。这种模式实现了发布-订阅机制,是事件…

Apache Struts2 远程命令执行漏洞(S2-052)

一、漏洞概述 S2-052 是 Apache Struts2 框架中一个高危的远程代码执行漏洞(CVE-2017-9805),由安全研究人员于 2017 年发现并公开。该漏洞源于 Struts2 的 REST 插件在使用 XStream 组件处理 XML 反序列化时,未对用户输入的 XML 数…

RS触发器Multisim电路仿真——硬件工程师笔记

目录 1 RS触发器基础知识 1.1 工作原理 1.2 电路结构 1.3 特点 1.4 应用 1.5 设计考虑 1.6 总结 2 与非门实现基本RS触发器 2.1 电路结构 2.2 工作原理 2.3 特点 2.4 总结 3 或非门实现基本RS触发器 3.1 电路结构 3.2 工作原理 3.3 特点 3.4 总结 4 与非门实…

提示技术系列(12)——程序辅助语言模型

什么是提示技术? 提示技术是实现提示工程目标的具体技术手段,是提示工程中的“工具库”。 什么又是提示工程? 提示工程是指通过设计、优化和迭代输入到大语言模型(LLM)的提示(Prompt)&#xff…

明远智睿H618:开启多场景智慧生活新时代

在数字化浪潮的推动下,智能设备正深刻地改变着我们的生活方式。明远智睿H618以其强大的功能和卓越的性能,在家庭娱乐、商业展示、教育培训和智能家居控制等多个领域展现出巨大的应用潜力,开启了多场景智慧生活的新时代。 家庭娱乐&#xff1…

探秘展销编辑器:相较于传统展销的卓越优势与甄选指南​

在竞争激烈的商业环境中,企业期望通过展销活动提升品牌知名度、推广产品和拓展市场,但传统展销方式存在诸多难题。一是场地限制,优质场地稀缺、租金贵、档期紧,场地空间和布局也不一定合适;二是展示形式单一,多为静态展…

第31篇:块设备与字符设备管理深度解析(基于OpenEuler 24.03)

块设备与字符设备管理深度解析(基于OpenEuler 24.03) 文章目录 块设备与字符设备管理深度解析(基于OpenEuler 24.03)一、设备基础概念体系1.1 块设备的核心特性与分类1.2 字符设备的流式数据模型1.3 设备标识系统:主设…

Django Channels WebSocket实时通信实战:从聊天功能到消息推送

引言 在Web开发中,实时通信功能(如在线聊天、实时通知、数据推送)已成为许多应用的核心需求。传统的HTTP协议由于其请求-响应模式的限制,无法高效实现实时通信。WebSocket作为一种全双工通信协议,为实时Web应用提供了…

day52 神经网络调参指南

目录 随机种子 内参的初始化 神经网络调参指南 参数的分类 调参顺序 初始化参数 batchsize的选择 学习率调整 激活函数的选择 损失函数的选择 模型架构中的参数 正则化系数 其他补充 随机种子 import torch import torch.nn as nn# 定义简单的线性模型&#xf…

.NET9 实现斐波那契数列(FibonacciSequence)性能测试

在 .NET 平台上实现 斐波那契数列 并使用 BenchmarkDotNet 进行性能测试&#xff0c;是评估不同算法实现方式性能表现的一种高效且标准化的方法。通过该方式&#xff0c;可以对比递归、迭代、记忆化递归以及结合高性能优化技术&#xff08;如 Span<T>、Memory<T> 和…

三、docker软件安装:gitlab,nexus,mysql8,redis,nacos,nginx

目录 1.gitlab安装 2.nexus安装 (1)下载启动 (2)设置中央仓库远程地址 (3)配置maven的settings.xml 3.mysql8安装 4.redis安装 5.nacos安装 6.nginx安装 1.gitlab安装 #创建目录 cd /usr/local/ mkdir docker cd docker/ mkdir gitlab_docker cd gitlab_docker…