Modbus TCP Server端(附超全注释)

2023-05-16

实验项目名称 Modbus TCP实验

  • 一、实验目的
  • 二、实验内容
  • 三、实验环境
  • 四、设计方案
  • 五、实验结果及分析(或设计总结)
  • 六、完整代码
    • 6.1 server.c
    • 6.2 respond.c
    • 6.3 respond.h

开发语言:C
开发平台:VS2019
开发工具:Visual studio 2019、Modbus/TCP Master

学习Modbus见:Modbus协议中文手册

获取Modbus TCP Master见:Modbus TCP Master

完整代码见文末,我会修改一点内容,请读者自行发现并改正,练习练习动手能力哈。

一、实验目的

熟悉并掌握Modbus协议,能用代码实现基于modbus协议的简单应用。

二、实验内容

(1)编写一个Modbus-TCP程序,用modbus Poll等模拟主站设备。从站设备具有16路DI、16路DO以及16路AI(从站可用曲线模拟)和16路AO(从站可用曲线模拟)。

(2)除了完成过程控制量的数据输入和输出外(使用已有的功能代码完成),还需要完成以下几个功能:

  1. 提供Modbus TCP的状态检查,检查系统是否正常、每个AI、AO、DI、DO通道是否正常;
  2. 自定义一个命令,实现对这些AI、AO、DI、DO通道选配,如果本次采集只采集8路DI和8路AO;
  3. 每次主从通信过程应该包括以下流程:
    (1) 首先主站轮询从站的状态;
    (2) 接着,从站发出响应,如果是OK,那么执行下一步,否则等待主站下一次轮询状态;
    (3) 主站对从站进行配置,配置DI/AI、DO /AO使能、采样周期;
    (4) 从站如果响应OK的话,执行下一步,否则等待主站的配置命令;
    (5)主站和从站进行数据交换和轮询。
    (6) 有通信的结束和退出命令。

三、实验环境

操作系统:Windows10

开发工具:Visual studio 2019、Modbus/TCP Master

四、设计方案

    本次实验使用TCP/IP来进行modbus协议的传输,主要使用了windows下的winsock2及其相关静态链接库ws2_32.lib,使用socket(套接字)进行主从机的连接。

    连接前,先进行从机(server)自检,检查AI、AO、DI、DO的数据是否已经准备好。我在从机部分用四个数组代替AI、AO、DI、DO,如图所示,所以自检OK。
在这里插入图片描述

    自检完成后,创建从机套接字,并将其与使用的电脑当前IPV4地址和相关端口进行绑定。绑定后将绑定状态输出到控制台。

    接着进入监听状态,当有主机连接进来时在控制台打印连接成功的信息。使用accept()函数阻塞程序运行,直到新的请求到来。每次将新的请求放入缓冲区(请求队列),处理完毕后再从缓冲区读取请求,并在while循环中,使用solve_all(SOCKET clnSock, byte request[])函数来判断请求的类型,并转到相应的处理函数。处理完后重置相应的缓冲区。solve_all()函数的实现如下。
在这里插入图片描述

注:由于modbus
tcp的报文帧格式如下,所以通过switch语句判断缓冲区的第8位:buff[7],即可直到功能码的类型。在这里,我只简单实现了01、02、03、04功能码,其他功能码类似,有一些在RTU中做了实现。

在这里插入图片描述

    这里再简单看一个功能码的实现,完整程序见附录或者压缩包。以01功能码为例进行说明:由于我将AI、AO、DI、DO都设置为16路,而DI、DO是以位为基本单位读写,而AI、AO是以字(这里是16位)为基本单位读写的,所以对于DI、DO的byte型数组只需要2个元素,而后者则需要32个元素。

    01功能码是读线圈/离散量的输出状态即ON/OFF。先通过报文的第12位(实际应该是第11、12个字节,但这里只用了16路,所以第11个字节为0x00,不予考虑)判断要读取的点的个数,再确定要返回的字节数,当读取的点数不超过8就返回一个字节,否则返回2个字节数据。相应的,还需要修改返回报文的第六位即这一位后面的字节数。除此之外,请求和响应的前8个字节是相同的。而响应报文的第九位是数据区的字节长度,即程序中的n,要说明的是在使用modbus tcp master软件测试时需要将n乘以2才能正确显示。再将第九位后面的区域填充为数据即可。最后用send()函数返回响应,同时在控制台输出请求、响应的内容。
在这里插入图片描述

    整个程序的流程图如下:

在这里插入图片描述

五、实验结果及分析(或设计总结)

(1)先查看本机IP地址,在程序中修改为今天的IP。
在这里插入图片描述在这里插入图片描述

(2)功能码测试
未连接时:
在这里插入图片描述
在这里插入图片描述

02功能码:
在这里插入图片描述
在这里插入图片描述

03功能码:
在这里插入图片描述
在这里插入图片描述

01与02,03与04相似,此处不再贴图。

六、完整代码

6.1 server.c

/*
* File_name:server.c
* Author:dahu
* Description:modbus tcp socket主要实现源文件
* Time:2021-04-21
* encoding:UTF-8
* Version:1.0
*/


/*********************************************************************
*                          Modbus-TCP报文帧格式
* |-----------------MBAP报头------------------|-----PDU-----|
* 
* 事务处理标识箱    协议表示符    长度    单元标识符   功能码   数据     
* 
    2Bytes          2Bytes    2Bytes    1Bytes    1Bytes  nBytes
exp:00 00         00  00      00 06     01         03     00 00   00 0A
**********************************************************************/


#include<stdio.h>
#include<winsock2.h>
//#include"scom.h"
#include"respond.h"

#pragma comment(lib,"ws2_32.lib")                //使用静态链接库

#define BUF_SIZE 20                              //缓冲区大小
#define Request_Queue_len 20                     //请求队列最大长度 

const char *server_addr = "172.20.10.3";       //服务器IP地址
short port = 502;                                //服务器端口号  

void TCP_server(short port,const char *p);       //TCP服务器函数声明
void STM32_IO(void);                             //与STM32通信,有点问题,没使用到,用的模拟方法实现
void init();                                     //从站状态检查,本来应该是STM32开机自检,由于用的是模曲线拟,基本上没什么用



int main() {
	//初始化 DLL
	WSADATA wsaData;   
	WSAStartup(MAKEWORD(2, 2), &wsaData);        //初始化,以指明 WinSock 规范的版本

	init();
	TCP_server(port,server_addr);
	//STM32_IO();

	WSACleanup();                                 //终止 DLL 的使用
	return 0;
}


/*********************************************************************************************
* 名称:main(short port,const char* p)
* 功能:创建tcp服务器,与client通信
* 入口参数:port:端口号;p:ip地址,本机ipv4地址
* 返回参数:无
* 说明:无
**********************************************************************************************/
void TCP_server(short port,const char* p) {
	/*Windows下的socket函数原型:
	SOCKET socket(int af, int type, int protocol);
	Windows 不把套接字作为普通文件对待,而是返回 SOCKET 类型的句柄,如:
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	*/
	SOCKET server_socket;                                     //创建一个套接字,参数(地址簇,socket类型,使用的协议) 
	server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


	struct sockaddr_in server_addr;                            //sockaddr_in结构体,可在ws2def.h中查看原型
	/*memset()函数原型是:extern void* memset(void* buffer, int c, int count)
	buffer:为指针或是数组, c:是赋给buffer的值,count:是buffer的长度.
	这个函数在socket中多用于清空数组.如:原型是memset(buffer, 0, sizeof(buffer))*/
	memset(&server_addr, 0, sizeof(server_addr));              //每个字节都用0填充
	server_addr.sin_family = AF_INET;                          //使用IPv4地址
	server_addr.sin_addr.s_addr = inet_addr(p);                //具体的IP地址,inet_addr是比较老的定义,要取消SDL检查。或者用inet_pton()函数
	server_addr.sin_port = htons(port);                        //端口

	/*Windows下的bind()函数原型:
	int bind(SOCKET sock, const struct sockaddr* addr, int addrlen);
	*/
	int bind_status = -1;
	bind_status = bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));           //将套接字与特定的IP地址和端口绑定起来

	if (bind_status == -1) {                                     //绑定状态监测,成功返回0,失败返回-1
		printf("绑定失败\n");
		exit(1);
	}
	else printf("套接字与IP地址、端口绑定成功\n");

	/*Windows下listeb()函数原型:
	int listen(SOCKET sock, int backlog);
	backlog 为请求队列的最大长度当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。
	如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列。
	*/
	int listen_status = -1;
	listen_status = listen(server_socket, Request_Queue_len);      //让套接字处于监听状态(并没有接收请求。接收请求需要使用 accept() 函数)

	if (listen(server_socket, 5) == -1) {                          //监听状态监测
		printf("监听失败\n");
		exit(1);
	}
	else printf("创建TCP服务器成功\nTCP连接正常,开始监听\n\n");

	/*Windows下accept()函数原型:
	SOCKET accept(SOCKET sock, struct sockaddr *addr, int *addrlen);
	accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。
	accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来
	*/
	SOCKADDR clntAddr;
	int nSize = sizeof(SOCKADDR);
	//char buff[BUF_SIZE] = { 0 };                                                   //缓冲区

	byte buff[BUF_SIZE] = {0};
	SOCKET clntSock = accept(server_socket, (SOCKADDR*)&clntAddr, &nSize);          //接收客户端请求
	printf("%d Link successfull\n", clntSock);


	while (1) {     

		//int recv(SOCKET sock, char *buf, int len, int flags);
		//int send(SOCKET sock, const char *buf, int len, int flags);

		int strLen = recv(clntSock, buff, BUF_SIZE, 0);         //接收客户端发来的数据,recv返回的是字节数

		if (strLen = 0)
			printf("客户端连接关闭\n\n");
		else if (strLen < 0) 
			printf("Linking Error");

		printf("\n\n**************************************************************************************************\n");
		//int length = buff[5];                                  //MBAP报文头,2+2+2+1   功能码1+起始地址2+数量2
		printf("收到报文为:\n");
		for (int i = 0;i < 12;i++)printf("0x0%x ", buff[i]);     //显示主站的请求报文
		printf("\n");

		solve_all(clntSock,buff);                                //根据功能码进行相应处理,从站返回相应报文

		memset(buff, 0, BUF_SIZE);                               //重置缓冲区
		//Sleep(1000);
	}

	closesocket(server_socket);                                   //关闭套接字
}




/*********************************************************************************************
* 名称:init()
* 功能:服务器端(从机)开机自检,但我没连接stm32,所以这个函数暂时是个空壳子
* 入口参数:无
* 返回参数:无
* 说明:无
**********************************************************************************************/
void init(void) {
	printf("从站状态检查...");
	printf("\n从站状态正常\n");
}




/*********************************************************************************************
* 名称: STM32_IO()
* 功能:与32通信,实现modbus tcp的AI、AO等
* 入口参数:无
* 返回参数:无
* 说明:调试不成功,暂时没使用
**********************************************************************************************/
void STM32_IO(void) {
	int data[9];  //
	HANDLE hcom;  //声明串口操作句柄
	hcom = open_scom("COM3", 9600, NOPARITY, 8, 1);//打开串口
	while (1)
	{
		read_scom(hcom, data);  //读串口
		// do someting;
		//break
		//printf("%d\n", data);
	}
	
	close_scom(hcom);         //关闭串口
}

6.2 respond.c

/*
* File_name:respond.c
* Author:dahu
* Description:定义了不同功能码的响应函数
* Time:2021-04-21
* encoding:UTF-8
* Version:1.0
*/


#include<stdio.h>
#include"respond.h"



/*********************************************************************************************
* 功能:模拟16路DI、DO、AI、AO
* 说明:使用的Modbus/TCP master ,使用了01 02 03 04功能码
*      前两个以bit为基本单位,16路即2bytes;后两个以word为基本单位,16路即32bytes(16words)。
* 注意:连续两个寄存器之间存在字节序和大小端的问题,需注意
*********************************************************************************************/
byte coil[2] = {0x00,0x00};    //读线圈/离散量输出状态(ON/OFF)   01    bit   16路DO:0000 0000 0000 0000(高到低)
byte relay[2] = {0x0f,0x06};   //读离散量输入值(ON/OFF)         02    bit   16路DI:0000 0110 0000 1111(高到低)
byte holding_reg[32] = {0x01,0x01,0x01,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,
						0x00,0x01,0x00,0x02,0x00,0x03,0x00,0x04,0x00,0x05,0x00,0x06,0x00,0x07,0x00,0x08,};     
                               //读保持寄存器值                   03    word  (响应报文按字节来的,这里不用word定义了)
byte input_reg[32] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};       
                               //读输入寄存器值                   04    word    全为0x0101,即257




/*********************************************************************************************
* 名称:solve_01(SOCKET clntSock, byte request[], byte coil[])
* 功能:01功能码,读线圈/离散量输出状态
* 入口参数:clnSock:客户端socket,request:接收数据缓冲区,coil:事先准备好的线圈/离散量状态输出值
* 返回参数:无
* 说明:收到报文的关键部分为:01(1byte)+ 起始地址(2bytes)+ 寄存器数(2bytes)。
*      例如: 02 00 00 00 06表示读取0x0000开始的6个线圈的状态(1个线圈占用1位,共1个字节)
*      返回报文关键部分为:02(1byte)+ N(1byte)+ n=N/N+1字节状态(n bytes)
*      对上诉例子的响应:02 01 01
*上面只是关键部分报文分析,完整报文符合server.c中我写的 Modbus TCP报文格式
**********************************************************************************************/
void solve_01(SOCKET clntSock, byte request[], byte coil[]) {
	int len, n;
	len = request[11];                                                     //需要读取的点的个数
	n = (len % 8) == 0 ? (len / 8) : (len / 8 + 1);                        //对应的的字节数
	byte send_buff[8 + 3] = { 0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x02 };   //返回数据缓冲区,前八个字节不变(除了长度位),后面最多3个字节
	send_buff[5] = 2 + 1 + n;                                              //确定响应报文第六位,即后续报文长度:01+02+n+n bytes data
	send_buff[8] = 2 * n;                                                  //我用的是Modbus/TCP这个软件来测试的,软件有点小问题,n要乘以2,正确的报文这里不需要乘以2  
	for (int i = 0;i < n;i++) {
		send_buff[i + 9] = coil[i];
	}
	printf("\n该指令为读线圈/离散量状态输出即DO,返回内容应该为:\n");
	for (int i = 0;i < 8 + 1 + n;i++)printf("0x0%x ", send_buff[i]);
	printf("\n**************************************************************************************************");
	send(clntSock, send_buff, 8 + 1 + n, 0);                               //响应请求
}




/*********************************************************************************************
* 名称:solve_02(SOCKET clntSock, byte request[], byte relay[])
* 功能:02功能码,读离散量输入
* 入口参数:clnSock:客户端socket,request:接收数据缓冲区,relay:事先准备好的离散量输入值
* 返回参数:无
* 说明:同01功能码
**********************************************************************************************/
void solve_02(SOCKET clntSock, byte request[], byte relay[]) {
	int len,n;
	len = request[11];                                                   //需要读取的点的个数
	n = (len % 8) == 0 ? (len/8):(len/8+1);                              //对应的的字节数
	byte send_buff[8 + 3] = { 0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x02 }; //返回数据缓冲区,前八个字节不变(除了长度位),后面最多3个字节
	send_buff[5] = 2+1+n;                                                //确定响应报文第六位,即后续报文长度:01+02+n+n bytes data
	send_buff[8] = 2*n;                                                  //我用的是Modbus/TCP这个软件来测试的,软件有点小问题,n要乘以2,正确的报文这里不需要乘以2  
	for (int i = 0;i < n;i++) {
		send_buff[i + 9] = relay[i];
	}
	printf("\n该指令为读离散量输入即DI,返回内容应该为:\n");
	for (int i = 0;i < 8+1+n;i++)printf("0x0%x ", send_buff[i]);
	printf("\n**************************************************************************************************");
	send(clntSock, send_buff, 8+1+n, 0);                                 //响应请求
}




/*********************************************************************************************
* 名称:solve_03(SOCKET clntSock, byte request[], byte holding_reg[])
* 功能:03功能码,读保持寄存器
* 入口参数:clnSock:客户端socket,request:接收数据缓冲区,holding_reg:事先准备好的保持寄存器
* 返回参数:无
* 说明:类似01功能码,不在赘述
**********************************************************************************************/
void solve_03(SOCKET clntSock,byte request[],byte holding_reg[]) {
	int len, n;
	len = request[11];                                                       //需要读取的寄存器的个数
	n = 2 * len;                                                             //对应的的字节数
	byte send_buff[8 + 33] = { 0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x03 };    //返回数据缓冲区,前八个字节不变(除了长度位),后面最多33个字节
	send_buff[5] = 2 + 1 + n;                                                //确定响应报文第六位,即后续报文长度:01+02+n+n bytes data
	send_buff[8] = n;                                                        //我用的是Modbus/TCP这个软件来测试的,软件有点小问题,n要乘以2,正确的报文这里不需要乘以2  
	for (int i = 0;i < n;i++) {
		send_buff[i + 9] = holding_reg[i];
	}
	printf("\n该指令为读保持寄存器,返回内容应该为:\n");
	for (int i = 0;i < 8 + 1 + n;i++)printf("0x0%x ", send_buff[i]);
	printf("\n**************************************************************************************************");
	send(clntSock, send_buff, 8 + 1 + n, 0);                                 //响应请求
}




/*********************************************************************************************
* 名称:solve_04(SOCKET clntSock, byte request[], byte input_reg[])
* 功能:04功能码,读输入寄存器
* 入口参数:clnSock:客户端socket,request:接收数据缓冲区,relay:事先准备好的离散量输入值
* 返回参数:无
* 说明:同01功能码
**********************************************************************************************/
void solve_04(SOCKET clntSock, byte request[], byte input_reg[]) {
	int len, n;
	len = request[11];                                                       //需要读取的寄存器的个数
	n = 2 * len;                                                             //对应的的字节数
	byte send_buff[8 + 33] = { 0x00,0x00,0x00,0x00,0x00,0x06,0x01,0x04 };    //返回数据缓冲区,前八个字节不变(除了长度位),后面最多33个字节
	send_buff[5] = 2 + 1 + n;                                                //确定响应报文第六位,即后续报文长度:01+02+n+n bytes data
	send_buff[8] = n;                                                        //我用的是Modbus/TCP这个软件来测试的,软件有点小问题,n要乘以2,正确的报文这里不需要乘以2  
	for (int i = 0;i < n;i++) {
		send_buff[i + 9] = input_reg[i];
	}
	printf("\n该指令为读输入寄存器,返回内容应该为:\n");
	for (int i = 0;i < 8 + 1 + n;i++)printf("0x0%x ", send_buff[i]);
	printf("\n**************************************************************************************************");
	send(clntSock, send_buff, 8 + 1 + n, 0);                                 //响应请求
}






/*********************************************************************************************
* 名称:solve_all(SOCKET clnSock,byte request[])
* 功能:对 功能码进行判别,并转到相应的功能码的处理函数
* 入口参数:clnSock:客户端socket,request:接收数据缓冲区
* 返回参数:无
* 说明:无
**********************************************************************************************/
void solve_all(SOCKET clnSock,byte request[]) {
	switch (request[7]) {
		case 1:solve_01(clnSock,request,coil);break;
		case 2:solve_02(clnSock,request,relay);break;    //DI 读离散量输入
		case 3:solve_03(clnSock,request, holding_reg);break;
		case 4:solve_04(clnSock,request,input_reg);break;
	}
}

6.3 respond.h

#pragma once
#include<winsock2.h>

#ifndef _RESPOND_H_
#define _RESPOND_H_


void solve_01(SOCKET clntSock, byte request[], byte coil[]);
void solve_02(SOCKET clntSock, byte request[], byte relay[]);
void solve_03(SOCKET clntSock, byte request[], byte holding_reg[]);
void solve_04(SOCKET clntSock, byte request[], byte input_reg[]);


void solve_all(SOCKET clnSock, byte request[]);  


#endif
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Modbus TCP Server端(附超全注释) 的相关文章

  • 无法在运行 apache 服务器上访问 http://localhost:80

    在 ubuntu 14 04 中运行 apache 服务器时我得到 This webpage is not available 在浏览器中或 curl 7 Failed to connect to localhost port 80 Con
  • 由于将请求从主线程传递到工作线程,netty 中出现延迟?

    我有一些关于 Netty 服务器端 TCP IP 应用程序的问题 我想知道在将请求从老板线程传递到工作线程时是否会因为 netty 由于缺少配置等 而出现延迟 我在用 new OrderedMemoryAwareThreadPoolExec
  • Go TCP 读取是非阻塞的

    我正在尝试用 Go 创建服务器和客户端 我已经成功地与服务器和客户端进行通信 但我遇到的问题是golang中的TCP读取是非阻塞的 我想知道 golang 中的读取是否有可能像 C 中的读取一样阻塞 谢谢 EDIT 这是服务器的源代码 fu
  • PHP 上的多个 TCP 套接字请求

    是否可以使用 PHP 上的套接字服务器接受多个请求 并行 如果可以的话 怎样做 普通的 PHP 脚本无法接收多个请求 但如果你真的计划创建一个套接字服务器 作为 cmdline php 脚本启动 那么是的 这是可能的 调查http pear
  • 为什么我们可以将 sockaddr 转换为 sockaddr_in

    我明白为什么强制转换很有用sockaddr to sockaddr in 但我不明白这怎么可能 据我所知 它们的大小相同sockaddr in添加了sin zero使其大小相同 我想知道编译器如何知道从哪里获取信息sockaddr in如果
  • 在 Golang Server 中接受持久的 tcp 连接

    我正在尝试使用 Go 并且想创建一个 TCP 服务器 我可以通过 telnet 访问该服务器 发送命令并接收响应 const CONN HOST localhost CONN PORT 3333 CONN TYPE tcp func mai
  • 如何在Linux中打开端口[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我已经安装了 Web 应用程序 该应用程序在 RHEL centOS 上的端口 8080 上运行 我只能通过命令行访问该机器 我尝试从我的
  • 如何关闭 Grizzly 日志记录?

    如何关闭 Grizzly 的日志记录 我想关闭以下日志记录 Okt 18 2018 8 42 24 AM org glassfish grizzly http server NetworkListener start INFORMATION
  • 保存到服务器后,隐藏字符“\u0”添加到文件中

    我正在使用 Apache 服务器为 Web 开发网站提供服务 这样我就可以不断保存和编辑文件 我使用 Gulp for Sass 来连接和丑化 css 和 js 文件 一个月前 我的 js 和 css 文件遇到问题 似乎在文件下面添加了随机
  • Rails 的 Puma Systemd 配置不起作用

    我已经完成了一个使用 Ruby on Rails 构建的应用程序 现在我想将其托管在 AWS 上的 EC2 实例上 我已经为其配置了服务器 并且正在使用pumaHTTP服务器作为应用服务器 在生产中启动应用程序总是需要我运行RAILS EN
  • 让 WSO2 IOT 服务器作为 Windows 服务运行

    我在Server 2012R2上安装了WSO2 IOT Server 我安装了 YAJSW 包装器并按照 WSO2 说明进行配置 当我启动 runConsole bat 来配置 Windows 服务时 出现以下错误 我设置了 JAVA HO
  • TcpClient 在异步读取期间断开连接

    我有几个关于完成 tcp 连接的问题 客户端使用 Tcp 连接到我的服务器 在接受客户端后listener BeginAcceptTcpClient ConnectionEstabilishedCallback null 我开始阅读netw
  • 序列化是通过套接字发送数据的最佳选择吗?

    有人告诉我 序列化不是通过套接字发送数据的最佳方法 但他们说他们在一本书上读过一次 并且不确定更好的方法 因为他们以前没有真正做过网络 那么序列化是最好的方法还是有更好的方法 如果这有很大的不同的话 这也是一个游戏 通过搜索有关通过它发送对
  • 为什么我收到的数据包数据大小大于mss?

    我在两台 PC 上使用 ifconfig ethX mtu 300 修改了 MTU 并使用 netperf 测试网络 我用 WireShark 嗅探了 SYN 数据包中的 MSS 260 但我得到了一些大于 260 的数据包 为什么 嗅探器
  • Laravel Vue js spa 应用程序

    1 我想知道为什么人们使用两台服务器用 laravel 制作 vuejs SPA 我想我们可以用另一种方式 制定这样的路线 Route get any function return view index gt where any 并让 v
  • IIS 如何识别请求的是哪个站点?

    如果我在一台服务器上托管多个站点 并且 dns 服务器将不同的域名解析到同一地址 这是服务器的名称 那么 IIS 如何知道最终请求的是哪个站点 因此 客户端输入我的 1 站点地址 gt myrandomsite mydomain com 然
  • 为什么tcp终止需要4次握手?

    当连接建立时 有 客户端 SYN gt 服务器 客户端 客户端 ACK gt 服务器 当终止到来时 有 客户端 FIN gt 服务器 客户端 客户端 客户端 ACK gt 服务器 我的问题是为什么 和 不能像 那样设置在同一个包中 即ACK
  • ADB TCPIP 连接问题

    我有两台 Galaxy S3 其中一个已扎根 另一个则未扎根 因此 当我尝试通过本地网络连接它们时 计算机可以看到已root的计算机 但是正常的就卡在tcpip这一步了 所以 我写 adb tcpip 5555 It says restar
  • 如何知道哪个本地应用程序连接到我的套接字(Windows)

    我有一个绑定到某个 TCP 端口的 Windows 服务 该端口用于我的应用程序之间的 IPC 有没有一种编程 WinAPI WinSocket 等 方法可以知道哪个应用程序连接到我的端口 即在我的 Windows 服务中 我想获取连接到我
  • 通过 TCP/.NET SSLStream 发送文件很慢/无法正常工作

    我正在编写一个与 SSL 配合使用的服务器 客户端应用程序 通过SSLStream 它必须做很多事情 不仅仅是文件接收 发送 目前 它的工作原理是 只有一个连接 我总是使用从客户端 服务器发送数据SSLStream WriteLine 并使

随机推荐

  • EndNote文献管理(一)雾里看花

    简介
  • EndNote文献管理(二)基操勿六

    1 创建文献数据库并添加文献1 1创建文献数据库1 2在线检索1 3批量导入1 4导入知网文献 2 文献管理2 1文献标记与排序2 2文献速览与下载全文2 3文献阅读与批注 3 编辑参考文献格式 1 创建文献数据库并添加文献 1 1创建文献
  • SQL Server(2019) 实验一 数据库和表的建立

    数据库和表的建立 一 实验目的二 实验内容和要求2 1 数据库的创建 2 2 表的创建 查看 修改和删除 2 2 1 xff0e 表的创建 2 2 2 xff0e 向创建的表中添加数据记录 2 2 3 xff0e 修改表结构 xff08 找
  • SQL Server 中时间的几种表示

    在SQL Server中 xff0c 点开数据类型 xff0c 单单是时间这一类变量都有着多重数据类型 datetimetimestampdatetimedatetime2datetimeoffset 他们的显示效果如下 xff1a spa
  • SQL Server(2019) 实验二 单表查询

    单表查询 一 实验目的二 实验内容和要求2 1 表结构修改2 1 1 xff0e 在实验三的所建立的数据库中增加Teacher表 xff0c 结构如下 xff1a 2 1 2 xff0e 在实验三的所建立的数据库中增加Teaching表 x
  • SQL Server(2019)导入excel数据

    要导入的excel文件如图所示 xff0c 600个记录 操作步骤 xff1a 1 在要导入的数据库上右键 xff0c 任务 xff0c 导入数据 2 选择数据源为excel xff0c 选择相应excel文件 xff0c 选择excel版
  • SQL Server(2019)导出excel数据

    目标 xff1a 将Grademanager数据库中的test表导出为excel test表内容 xff1a 如图 xff0c 600条记录 操作步骤 xff1a 1 在相应数据库上右键 xff0c 任务 xff0c 导出数据 2 选择数据
  • 机器视觉特征提取介绍:HOG、SIFT、SURF、ORB、LBP、HAAR

    一 概述 这里主要记录自己的一些感悟 xff0c 不是很系统 想要详细系统的理论 xff0c 请参考文末的 图像处理之特征提取 个人不是专业cv工程师 xff0c 很多细节没有深究 xff0c 描述可能不严谨 在总结物体检测算法之前先把基础
  • ROS低调复习总结

    ROS复习 一 考试时间 形式 日期二 题型三 不知道随便写四 课程知识点 难点1 1 3章课后复习题1 1 单元测试一1 2 单元测试二1 3 单元测试三 2 第二章 ROS系统架构2 1 比较Topic与Service通信2 2 关闭一
  • 了解Web前端-1 Http基本原理

    HTTP基本原理 1 HTTP协议2 HTTP与Web服务器3 浏览器中的请求和响应1xx 信息2xx 成功3xx 重定向4xx 客户端错误5xx 服务器错误 1 HTTP协议 Hyper Text Transfer Protocol xf
  • 了解Web前端2-HTML语言

    HTML语言 1 什么是HTML2 了解HTML结构4 HTML的基本标签4 1 不是标签4 2 文件开始标签 96 96 4 3文件头部标签 96 96 4 4文件标题标签 96 96 4 5元信息标签 96 96 4 6页面的主体标签
  • 了解Web前端3-CSS层叠样式表

    CSS样式层叠表 1 CSS 概述2 属性选择器2 1属性选择器2 2属性和值选择器2 3属性和值的选择器 多值 3 类和ID选择器3 1ID选择器3 2类选择器3 3为特定元素使用class 1 CSS 概述 CSS是一种标记语言 xff
  • 了解Web前端4-JavaScript动态脚本语言

    JavaScript 动态脚本语言 1 页面中直接嵌入JavaScript代码2 连接外部JavaScript文件 JavaScript 是 web 开发人员必须学习的 3 门语言中的一门 xff1a HTML 定义了网页的内容CSS 描述
  • 爬虫の简介

    爬虫简介 一 什么是爬虫二 Python爬虫架构 一 什么是爬虫 爬虫 xff1a 一段自动抓取互联网信息的程序 xff0c 从互联网上抓取对于我们有价值的信息 二 Python爬虫架构 Python 爬虫架构主要由五个部分组成 xff0c
  • 一个不错的在线作图网站

    菜鸟教程的一个在线工具 连接 xff1a https c runoob com more shapefly diagram 优点 xff1a 没有广告 xff0c 不用关注微信公众号 xff0c 不用登陆 此外 xff0c 菜鸟还提供了其他
  • ABB机器人复习

    1 工业机器人最显著的特点 xff1a 2 工业气人的5种典型的结构 xff1a 3 认识示教器 xff1a 4 ABB机器人坐标系 xff1a 5 轴运动与线性运动 xff1a 1 轴运动 xff1a 2 线性运动 xff1a 6 重定位
  • step7basic的许可无法彻底完成

    安装博途并 后 xff0c 在项目中选择设备时可能会出现 xff1a step7basic的许可无法彻底完成 因为automation license manager中 的报错 原因 xff1a win10系统的更新 xff0c 导致软件不
  • 西门子学习第一章 S7-1200基础

    第一章 1 1 S7 1200系统概述 xff08 1 xff09 PLC 运用领域 xff08 2 xff09 S7 1200外观 xff08 3 xff09 西门子系列分类 1 2博途软件1 3 S7 1200系列PLC的硬件介绍 xf
  • 可见光的波长转换为RGB值颜色,光谱波长与RGBA分量,不同波长的光转换成不同的RGB值,JavaScript版本

    JS版本的光谱波长转换RGBA颜色值的方法 xff0c 在网上没找到 xff0c 后来领导发来一个C 43 43 版本的 xff0c 我对照着改为JS版 xff0c 有需要的朋友 可以参考 xff0c 代码如下 xff1a lt html
  • Modbus TCP Server端(附超全注释)

    实验项目名称 Modbus TCP实验 一 实验目的二 实验内容三 实验环境四 设计方案五 实验结果及分析 xff08 或设计总结 xff09 六 完整代码6 1 server c6 2 respond c6 3 respond h 开发语