La práctica de Wireshark captura paquetes de datos de red y utiliza programación C para completar el protocolo modbus y leer datos de temperatura y humedad del servidor en la nube.


prefacio

Tarea:
1.

Practique wireshark para capturar paquetes de red. Ejecute el programa "Crazy Chat Room" en dos computadoras (laptop win10 host y ubuntu virtual machine. Seleccione el modo puente para que la tarjeta de red obtenga dos direcciones IPv4 de subred) y capture paquetes a través de wireshark: 1) Analice la conexión de red de este programa
usando ¿Qué protocolo (TCP, UDP) y qué número de puerto es?
2) Intente encontrar la información de chat robada en el paquete de captura (los caracteres ingleses y los caracteres chinos pueden haber sufrido algún tipo de conversión de codificación, y el paquete de datos no está en texto sin formato) 3) Si la conexión de red usa TCP, analice cuándo se
establece un apretón de manos de 3 vías de conexión, apretón de manos de 4 vías cuando está desconectado; si es UDP, explique por qué el programa puede transmitir datos de chat entre varias computadoras (solo el mismo número de sala de chat) al mismo tiempo.

dos,

Utilice la programación en C para completar el protocolo modbus y leer los datos de temperatura y humedad del servidor en la nube:

Software:
Crazy Chat Room :
Enlace: Crazy Chat Room Código
de extracción : 1234
wireshark:
Enlace: wireshark
Código de extracción: 1234
RedPandaDE:
Enlace: RedPandaDE
Código de extracción: 1234


1. Sala de chat loca

Al realizar este experimento, necesitamos dos computadoras bajo la misma red de área local.

1. Configurar la red

Panel de control---->Redes e Internet---->Centro de redes y recursos compartidos---->Cambiar configuración del adaptador:
deshabilite otras puertas de enlace, dejando solo la red donde están conectadas las dos computadoras:

inserte la descripción de la imagen aquí

2. Crea una habitación

Ambas computadoras necesitan descargar Crazy Chat Room:

Haga clic en crazychat.exe para crear una sala:
inserte la descripción de la imagen aquí
Cree la sala número 8888 y asígnele el nombre:
inserte la descripción de la imagen aquí

3. Enviar mensajes el uno al otro

inserte la descripción de la imagen aquí

2. Wireshark captura paquetes de red

La instalación de wireshark es todo el camino a seguir y estar de acuerdo.

1. Encuentra el paquete correspondiente

Cada vez que enviamos un mensaje en la loca sala de chat, wireshark encontrará inmediatamente el paquete cuya dirección IP es la dirección de transmisión 255.255.255.255.
inserte la descripción de la imagen aquí

Del análisis de paquetes capturado en la figura anterior, sabemos que
este programa de chat utiliza el protocolo UDP y el número de puerto 255.255.255.255.

2. Analizar la información del paquete capturado

Haga doble clic en el paquete capturado para ver información específica:

Números:
inserte la descripción de la imagen aquí
Inglés:
inserte la descripción de la imagen aquí
Chino:

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

Del análisis de la figura anterior, sabemos que los caracteres y números ingleses se pueden ver normalmente en texto sin formato, pero los caracteres chinos no se pueden ver en texto sin formato después de codificarlos.Después de enviar tres códigos hexadecimales chinos idénticos, encontramos que tres bytes codifican un carácter chino y adivine la codificación. El formato es UTF-8.

3. Descripción general del protocolo Modbus

1. El protocolo Modbus es un protocolo de comunicación en serie publicado por Modicon (ahora Schneider Electric) en 1979 para el uso de la comunicación del controlador lógico programable (PLC). El protocolo Modbus es un protocolo de capa de aplicación, que se ha convertido en el estándar de la industria para los protocolos de comunicación en el campo industrial, y es un método de conexión de uso común entre dispositivos electrónicos industriales.
2. Modbus es un protocolo de arquitectura maestro/esclavo. Un nodo es el nodo maestro, y otros nodos que usan el protocolo Modbus para participar en la comunicación son nodos esclavos. Cada dispositivo esclavo tiene una dirección única. Solo el nodo designado como nodo maestro puede iniciar un comando. Todas las tramas de datos Modbus contienen un código de verificación para garantizar la corrección de la transmisión. Los comandos básicos de ModBus pueden indicar a un dispositivo esclavo que cambie un valor en uno de sus registros, controle o lea un puerto de E/S y ordene al dispositivo que envíe datos en uno o más de sus registros.

1. Principio del protocolo Modbus maestro/esclavo

El protocolo de enlace serie Modbus es un protocolo maestro-esclavo. Al mismo tiempo, solo se puede conectar una estación maestra al bus y una o más estaciones esclavas (número máximo 247) se pueden conectar al mismo bus serie. La comunicación Modbus siempre es iniciada por la estación maestra, cuando la estación esclava no recibe una solicitud de la estación maestra, no enviará datos. La estación maestra solo puede iniciar una transacción Modbus al mismo tiempo y las estaciones esclavas no pueden comunicarse entre sí.

inserte la descripción de la imagen aquí

2. Estructura general de la trama Modbus: unidad de datos de protocolo (PDU)

El protocolo Modbus define una unidad de datos de protocolo (PDU) simple independiente de la capa de comunicación subyacente. El mapeo del protocolo Modbus en un bus o red específicos puede introducir algunos campos adicionales en la unidad de datos de la aplicación (ADU).

inserte la descripción de la imagen aquí

3. Dos modos de transmisión en serie Modbus

Modo RTU : cada byte de 8 bits contiene dos caracteres hexadecimales de 4 bits. La ventaja es que a la misma velocidad de transmisión, se pueden transmitir más datos que ASCII, pero cada mensaje debe estar en transmisión continua de datos.

inserte la descripción de la imagen aquí

Modo ASCII : se requieren 2 caracteres ASCII para cada byte de 8 bits en la información, lo que tiene la ventaja de permitir que el intervalo de transmisión de caracteres alcance 1 s sin error;

inserte la descripción de la imagen aquí

4. Estructura de comunicación ModbusTCP

Dispositivos de comunicación para Modbus TCP/IP: Dispositivos cliente y servidor Modbus TCP/IP conectados a una red TCP/IP.
Dispositivos de interconexión como puentes, enrutadores o puertas de enlace que se interconectan entre redes TCP/IP y subredes de enlace serie.

inserte la descripción de la imagen aquí

4. La programación en C completa el protocolo modbus y lee los datos de temperatura y humedad del servidor en la nube.

Abra RedPandaDE y cree un nuevo proyecto:
inserte la descripción de la imagen aquí

1. Código de configuración

1. Inicialice el socket dll y conéctese al puerto correspondiente del servidor a través de IP:

WORD winsock_version = MAKEWORD(2,2);
	WSADATA wsa_data;
	if (WSAStartup(winsock_version, &wsa_data) != 0) {
    
    
		printf("Failed to init socket!\n");
		return 1;
	}
	
	SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (client_socket == INVALID_SOCKET) {
    
    
		printf("Failed to create server socket!\n");
		return 2;
	}
	
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	if (connect(client_socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
    
    
		printf("Failed to connect server: %ld !\n", GetLastError());
		return 3;
	}

2. Generar código de verificación:

uint16_t CRC_16(uint8_t *temp)
{
    
    
	uint8_t i,j;
	uint16_t CRC_1 = 0xFFFF;          //声明CRC寄存区,也就是步骤1
	for(i = 0;i < 6;i++)       //这里的for循环说的是步骤6中的重复步骤 2 到步骤 5
	{
    
    
		CRC_1 ^= temp[i]; //这里就是步骤2,进行异或运算
		for(j = 0;j < 8;j++)         //用来将异或后的低八位全部移出的for循环
		{
    
    
			if(CRC_1 & 0x01)         //判断低八位的最后一位是否为1,为1时执行下列语句,也就是步骤3说的移位判断与步骤5说的右移8次
			{
    
    
				/*一定要先移位,再异或*/
				CRC_1 >>=1;          //移位后再异或,就是步骤4
				CRC_1 ^= 0xA001;     //0xA001为0x8005的逆序
			}
			else                    //若不为1,则直接移位。
			{
    
    
				CRC_1 >>=1;
			}
		}
	}
	
	//	CRC_1 = (((CRC_1 & 0xFF)<<8) + (CRC_1>>8));
	//	printf("%04x\r\n",CRC_1);     //用于打印检测CRC校验码
	return(CRC_1);
}

3. Tomar datos de temperatura y humedad:

int ret = recv(client_socket, recv_data, BUFFER_SIZE, 0);
		if (ret < 0) {
    
    
			printf("Failed to receive data!\n");
			break;
		}
		recv_data[ret]=0; // correctly ends received string
		char yb[4],wd[4];
		for(int i=0;i<4;i++){
    
    
			//TODO
			yb[i] = recv_data[4+i];
			wd[i] = recv_data[8+i];
			
		}
		float mic = hexToDec(yb)/100.0;
		float strain_temp = hexToDec(wd)/100.0;
		printf("应变:%f\r\n",mic);
		printf("温度:%f\r\n",strain_temp);

4. Código completo

#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <winsock2.h>  
#include <math.h>
#include "stdint.h"
#define length_8 8    //定义一个宏,为传入8位16进制数的个数
#define PORT 8002
#define SERVER_IP "123.56.90.74"
#define BUFFER_SIZE 4196

const char* kExitFlag = "exit";


/* 返回ch字符在sign数组中的序号 */
int getIndexOfSigns(char ch)
{
    
    
	if(ch >= '0' && ch <= '9')
	{
    
    
		return ch - '0';
	}
	if(ch >= 'A' && ch <='F') 
	{
    
    
		return ch - 'A' + 10;
	}
	if(ch >= 'a' && ch <= 'f')
	{
    
    
		return ch - 'a' + 10;
	}
	return -1;
}
/* 十六进制数转换为十进制数 */
int hexToDec(char *source)
{
    
    
	int sum = 0;
	int t = 1;
	int i, len=4;
	char low,high;
	for(int i=0,j=7;i<4;i++){
    
    
		//TODO
		high = (source[i] & 0xf0)>>4;
		low = source[i] & 0x0f;
		sum += high*pow(16,j--)+low*pow(16,j--); 
	}
	return sum;
}



const unsigned char *fromhex(const char *str)
{
    
    
	static unsigned char buf[512];
	size_t len = strlen(str) / 2;
	if (len > 512) len = 512;
	for (size_t i = 0; i < len; i++) {
    
    
		unsigned char c = 0;
		if (str[i * 2] >= '0' && str[i*2] <= '9') 
			c += (str[i * 2] - '0') << 4;
		if ((str[i * 2] & ~0x20) >= 'A' && (str[i*2] & ~0x20) <= 'F') 
			c += (10 + (str[i * 2] & ~0x20) - 'A') << 4;
		if (str[i * 2 + 1] >= '0' && str[i * 2 + 1] <= '9') 
			c += (str[i * 2 + 1] - '0');
		if ((str[i * 2 + 1] & ~0x20) >= 'A' && (str[i * 2 + 1] & ~0x20) <= 'F')
			c += (10 + (str[i * 2 + 1] & ~0x20) - 'A');
		buf[i] = c;
	}
	return buf;
}

uint16_t CRC_16(uint8_t *temp)
{
    
    
	uint8_t i,j;
	uint16_t CRC_1 = 0xFFFF;          //声明CRC寄存区,也就是步骤1
	for(i = 0;i < 6;i++)       //这里的for循环说的是步骤6中的重复步骤 2 到步骤 5
	{
    
    
		CRC_1 ^= temp[i]; //这里就是步骤2,进行异或运算
		for(j = 0;j < 8;j++)         //用来将异或后的低八位全部移出的for循环
		{
    
    
			if(CRC_1 & 0x01)         //判断低八位的最后一位是否为1,为1时执行下列语句,也就是步骤3说的移位判断与步骤5说的右移8次
			{
    
    
				/*一定要先移位,再异或*/
				CRC_1 >>=1;          //移位后再异或,就是步骤4
				CRC_1 ^= 0xA001;     //0xA001为0x8005的逆序
			}
			else                    //若不为1,则直接移位。
			{
    
    
				CRC_1 >>=1;
			}
		}
	}
	
	//	CRC_1 = (((CRC_1 & 0xFF)<<8) + (CRC_1>>8));
	//	printf("%04x\r\n",CRC_1);     //用于打印检测CRC校验码
	return(CRC_1);
}

int main() {
    
    
	// 初始化socket dll。
	WORD winsock_version = MAKEWORD(2,2);
	WSADATA wsa_data;
	if (WSAStartup(winsock_version, &wsa_data) != 0) {
    
    
		printf("Failed to init socket!\n");
		return 1;
	}
	
	SOCKET client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (client_socket == INVALID_SOCKET) {
    
    
		printf("Failed to create server socket!\n");
		return 2;
	}
	
	struct sockaddr_in server_addr;
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.S_un.S_addr = inet_addr(SERVER_IP);
	if (connect(client_socket, (LPSOCKADDR)&server_addr, sizeof(server_addr)) == SOCKET_ERROR) {
    
    
		printf("Failed to connect server: %ld !\n", GetLastError());
		return 3;
	}
	
	char recv_data[BUFFER_SIZE+1];
	while (true) {
    
    
		uint8_t data[length_8];
		printf("0+传感器编号(1,2,3,4,5)0300010002\r\n");
		scanf("%s",data);
		uint16_t crc;
		unsigned char * cmd;
		char crc1[8];
		cmd = fromhex(data);
		crc = CRC_16(cmd);
		uint8_t a = 0xFF;
		for(int i=0;i<6;i++){
    
    
			//TODO
			crc1[i] = cmd[i];
		}
		crc1[6] = a & crc;
		crc1[7] = (crc >> 8) & a;
		
		if (send(client_socket, crc1, 8, 0) < 0) {
    
    
			printf("Failed to send data!\n");
			break;
		}
		
		int ret = recv(client_socket, recv_data, BUFFER_SIZE, 0);
		if (ret < 0) {
    
    
			printf("Failed to receive data!\n");
			break;
		}
		recv_data[ret]=0; // correctly ends received string
		char yb[4],wd[4];
		for(int i=0;i<4;i++){
    
    
			//TODO
			yb[i] = recv_data[4+i];
			wd[i] = recv_data[8+i];
			
		}
		float mic = hexToDec(yb)/100.0;
		float strain_temp = hexToDec(wd)/100.0;
		printf("应变:%f\r\n",mic);
		printf("温度:%f\r\n",strain_temp);
		
		
		//		printf("Receive data from server: \"%x\"\n",recv_data);
		if (strcmp(data,kExitFlag)==0) {
    
    
			printf("Exit!\n");
			break;
		}
	}
	
	closesocket(client_socket);
	WSACleanup();
	
	return 0;
}

2. Efecto

inserte la descripción de la imagen aquí


V. Resumen

Debido a que la dirección de transmisión de 255.255.255.255 se usa al enviar el mensaje, varias partes pueden recibir el mensaje. Comprender los principios básicos del protocolo de comunicación Modbus y el protocolo y la estructura de comunicación ModbusTCP.

6. Referencias

Use wireshark para capturar información de chat (comunicación udp en la red de área local)
use lenguaje c para completar el protocolo modbus y lea la información de temperatura y humedad del servidor en la nube

Supongo que te gusta

Origin blog.csdn.net/qq_52215423/article/details/128444683
Recomendado
Clasificación