Modelo de programación de red TCP desde la entrada hasta los conceptos básicos de combate reales, versión no concurrente de un solo servidor y un solo usuario


prefacio

  • Este artículo es solo para la situación en la que no sabe cómo usarlo después de aprender a programar redes en la escuela. Lo que puede obtener de este capítulo es el dominio del modelo TCP más básico.

Diagrama del modelo de programación:


Primero, el conocimiento básico necesario de la práctica de programación de redes.

  • dirección IP (dirección de 32 bits) : dirección de red + composición del número de host: puede identificar de forma única un host. . . . La dirección de red anterior es para determinar si está bajo el mismo segmento de red. . . . Bajo el mismo segmento de red, para distinguir diferentes computadoras, se usa la dirección IP. . . . . Pero la dirección IP no es necesariamente única para siempre, según la dirección de la conexión de red, la red está conectada en diferentes lugares, y cada vez que se vuelve a conectar la red, la dirección IP puede ser diferente... La El núcleo es que la ip no es La dirección física es necesaria para conectarse a la red. . . .                                                                                                                      
  • dirección mac : en comparación con la dirección IP anterior, la dirección mac es una dirección física que siempre se determina de forma única, lo que equivale a su tarjeta de identificación y se determina de forma única en el mundo... Porque no es como una IP basada en cambiarán las conexiones de red de diferentes segmentos de red....       
  • Número de puerto (port) (16 bits) : identifica de forma única un proceso. . . . Aquí hablamos de por qué se necesitan los números de puerto. . . . . Si es necesario establecer una conexión de comunicación entre dos procesos en el mismo host, o si es necesario determinar una conexión entre diferentes procesos en diferentes hosts, no es suficiente tener solo una dirección IP en este momento, porque es imposible establecer una conexión única. determinar un proceso. ....                                                                                                         
  • ¿Cuál es el propósito de establecer una conexión de red, cuál es la esencia ?     Cualquier servidor de red y cliente de red, si desea llevar a cabo una comunicación de datos normal, debe usar el número de puerto para identificar de forma única su propio proceso...
  • Identificación de proceso única   : dentro del mismo sistema operativo, un proceso se puede vincular a un número de puerto, y el número de puerto identifica de forma única un proceso único en un host a nivel de red   
  • ip + puerto    : Identifica un proceso único en toda la red     
  • La comprensión de socket : significado en inglés: socket, mi comprensión simple, abre un agujero al mismo tiempo en el lado del servidor y en el lado del cliente, y luego el envío y la recepción de datos se realizan a través de este agujero, así que entiéndalo, se siente como obtener un cable de red virtual, un extremo se conecta al cliente, el otro extremo se conecta al servidor y luego se comunica... Abra un puerto, lea datos del puerto y envíe datos al puerto
  • Análisis detallado de la creación de sockets  : capa IP (capa de red): si usar IPV4 o IPV6, si usar TCP o UDP para la capa de transporte (este artículo solo estudia TCP) Para TCP, usamos IPV4 (AF_INET) + TCP (SOCK_STREAM )
  • El formato de almacenamiento de transmisión de red de la transmisión de datos está unificado : la máquina tiene la diferencia entre las máquinas big-endian y las máquinas small-endian.Para distinguir entre las máquinas big-endian y las máquinas little-endian es verificar si la dirección baja almacena byte bajo datos o datos de byte alto, y la dirección baja almacena datos de byte bajo. Datos de sección (almacenamiento little endian), datos de byte alto de almacenamiento de byte bajo (almacenamiento big endian).Es precisamente porque diferentes máquinas almacenan datos en diferentes formatos, pero ¿cómo definimos correctamente el formato de almacenamiento de estos datos en la red? ????   
  • Solución : unificar en un orden de bytes de red fijo: el orden de bytes de la red transmite la información de la dirección del flujo de datos de acuerdo con el formato de almacenamiento big-endian, por lo que si se trata de una máquina big-endian, podemos transmitirla directamente sin convertir los datos La máquina final debe convertirse en orden de bytes de red y pasarse para determinar la información de la dirección del flujo de datos.
  • Los siguientes comentarios de código ayudan a comprender: h : host (host) n : red (red) l : larga (dirección IP de 32 bits) s : corta (dirección IP de 16 bits)
  • Puerto)   
  • SYNOPSIS
           #include <arpa/inet.h>
    
           uint32_t htonl(uint32_t hostlong);
    
           uint16_t htons(uint16_t hostshort);
    
           uint32_t ntohl(uint32_t netlong);
    
           uint16_t ntohs(uint16_t netshort);
    
    DESCRIPTION
           The htonl() function converts the unsigned integer hostlong from host byte order to network byte order.
    
           The htons() function converts the unsigned short integer hostshort from host byte order to network byte order.
    
           The ntohl() function converts the unsigned integer netlong from network byte order to host byte order.
    
           The ntohs() function converts the unsigned short integer netshort from network byte order to host byte order.
    
           On  the  i386 the host byte order is Least Significant Byte first, whereas the network byte order, as used on the Internet, is Most Significant
           Byte first.
    

  • Luego realice un análisis gráfico de la estructura sockaddr   
  • La estructura y el análisis de struct sockaddr_in son los siguientes :    
  1.  sin_family: familia de protocolos (dominio) escriba directamente AF_INET para representar el protocolo de red IPV4   
  2.  sin_port: número de puerto de 16 bits (tenga en cuenta el orden de los bytes)
  3.  sin_addr: dirección IP de 32 bits (tenga en cuenta el orden de los bytes)  

En segundo lugar, el análisis del método de llamada al sistema.

1. enchufe

  •  returnval   : En caso de éxito, se devuelve un descriptor de archivo para el nuevo socket. En caso de error, se devuelve -1 y errno se establece de manera adecuada. El descriptor de archivo de socket se devuelve en caso de éxito, -1 en caso de falla

2. enlazar

 Análisis de configuración de parámetros específicos de la estructura :

INADDR_ANY   : Es esencialmente una macro, que puede representar cualquier dirección IP local, porque el servidor puede tener múltiples tarjetas de red, y cada tarjeta de red puede estar vinculada a múltiples direcciones IP, por lo que la configuración puede monitorear todas las direcciones IP, hasta y un cierto Cuando el cliente establece una conexión, determina qué dirección IP usar (para decirlo sin rodeos, es cualquier dirección IP posible en el servidor comodín para evitar el problema de los errores de configuración de IP causados ​​por múltiples IP en una sola máquina)

return val : devuelve 0 en caso de éxito, -1 en caso de error.

3.escuchar

 return val : devuelve 0 en caso de éxito, -1 en caso de falla y el sockfd entrante se convierte en el socket de escucha.

Conector de escucha (listenfd)  : el único conector de escucha en el mundo está en el servidor. Preste especial atención al hecho de que el conector de escucha es el único en el mundo y siempre está en estado de escucha (a diferencia de connfd: connectfd : toma de conexión en el siguiente texto)

Conector de conexión (connfd)    : se genera un nuevo connfd cada vez que se establece una conexión. . . .

Los ejemplos de vida comprenden enchufes de escucha y enchufes de conexión, que también se pueden llamar enchufes de servicio:

Por ejemplo, en un hotel de alta gama, siempre hay un mesero que da la bienvenida al auto en la puerta. Este mesero ha estado monitoreando la puerta. Cuando lleguen los invitados, serán invitados a pasar. Después de entrar, otro mesero los atenderá. Este hotel es de relativamente alta gama. Después de entrar, el camarero siempre está alineando el servicio. Cada persona que viene aquí necesita una nueva toma de servicio (toma de conexión) para alinear el servicio hasta que se vaya. En cuanto a la toma de escucha en el puerta, siempre es constante.El oyente de que cliente viene, que quiere establecer una conexión para trabajar....

4.aceptar

Modelo de código:

mientras (1) {

        clientaddr_len = sizeof(clientaddr);

        connfd = accept(listenfd, (SA*) &clientaddr, &clientaddr_len);

        código de lógica de servicio

        close(connfd); //El servicio finaliza y cierra la conexión..

 return val : el valor de retorno es exactamente el   connfd anterior , conectando el socket, cada vez que se realiza una conexión, se devolverá un nuevo connfd, por lo que la función de aceptación generalmente se coloca en un bucle infinito para recibir continuamente la solicitud de conexión del cliente, y Alineados para el servicio....

5.conectar

return val : devuelve 0 en caso de éxito, -1 en caso de error

Función auxiliar: la secuencia de publicaciones debe usar la conversión entre la dirección IP de la cadena y sin_addr: 


3. Código de caso real

1. Lado del servidor

el código se muestra a continuación:

[tangyujie@VM-4-9-centos Serve]$ cat server.c
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>

#define SERVE_PORT 12345
#define ERR_EXIT(m) \
	do { perror(m); exit(EXIT_FAILURE); } while (0)
typedef struct sockaddr SA;

int listenfd;								//设置全局监听套接字, 方便关闭
void handle(int signo) {
	fprintf(stdout, "ByeBye!\n");
	close(listenfd);
	exit(EXIT_SUCCESS);
}

int main() {
	signal(SIGINT, handle);
	int connfd;
	struct sockaddr_in serveAdd, clientAdd;
	socklen_t clientAdd_len;
	char ipbuff[256];
	//创建套接字
	if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		ERR_EXIT("socket");	//协议家族 服务类型(套接字类型), 协议弃用(0)
	}
	//确定服务端地址簇
	bzero(&serveAdd, sizeof(serveAdd));					//清0
	serveAdd.sin_family = AF_INET;
	serveAdd.sin_port = htons(SERVE_PORT);
	serveAdd.sin_addr.s_addr = htonl(INADDR_ANY);		//注意转网络字节序
	//bind 端口 地址信息
	if (bind(listenfd, (SA*)&serveAdd, sizeof(serveAdd)) == -1) {
		ERR_EXIT("bind");
	}
	//开始监听..
	if (listen(listenfd, 3) == -1) {
		ERR_EXIT("listen");
	}
	printf("Accepting connections..\n");
	//循环不断的接收客户的连接请求进行服务
	while (1) {
		clientAdd_len = sizeof(clientAdd);
		if ((connfd = accept(listenfd, (SA*)&clientAdd, &clientAdd_len)) == -1) {
			ERR_EXIT("accept");
		}
		printf("recieve connection from ip is %s and port is %d\n",
			inet_ntop(AF_INET, &clientAdd.sin_addr, ipbuff, sizeof(ipbuff)), 
			ntohs(clientAdd.sin_port));
		//服务
		while (1) {
			char buff[1024] = {0};
			int i;
			int n = read(connfd, buff, sizeof(buff));		//读数据
			if (n == -1) {
				ERR_EXIT("read");
			} 
			if (n == 0) {									//说明客户端主动断开连接
				break;
			}
			//处理数据, 简单的小写字符转大写
			for (i = 0; i < n; ++i) {
				buff[i] = toupper(buff[i]);
			}
			//写回
			write(connfd, buff, n);
		}
    fprintf(stdout, "ip %s and port is %d interrupt connfd\n",
        ipbuff, ntohs(clientAdd.sin_port));
		close(connfd);										//服务结束断开连接
	}
    return 0;
}

2. Cliente

el código se muestra a continuación:

[tangyujie@VM-4-9-centos Serve]$ cat client.c
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <signal.h>
#include <string.h>

#define SERVE_PORT 12345								//端口号
#define ERR_EXIT(m)\
	do { perror(m); exit(EXIT_FAILURE); } while (0)     //错误处理
typedef struct sockaddr SA;								
int sockfd;												//设置全局, 方便关闭
void handle(int signo) {
	fprintf(stdout, "ByeBye!\n");
	close(sockfd);
	exit(EXIT_SUCCESS);
}
int main(int argc, char* argv[]) {
	if (argc != 2) {
		fprintf(stderr, "%s <ip>", argv[0]);
		close(EXIT_FAILURE);
	}
	signal(SIGINT, handle);
	struct sockaddr_in serveAdd;
	//创建套接字
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		ERR_EXIT("socket");	//协议家族 服务类型(套接字类型), 协议弃用(0)
	}
		//确定服务端地址簇
	bzero(&serveAdd, sizeof(serveAdd));					//清0
	serveAdd.sin_family = AF_INET;
	serveAdd.sin_port = htons(SERVE_PORT);
	//将传入的ip字符串转换为 sin_addr
	if (inet_pton(AF_INET, argv[1], &serveAdd.sin_addr) == -1) {
		ERR_EXIT("inet_ntop");
	} 
	//不需要绑定端口号 系统随机分配一个临时端口号, 直接连接
	if (connect(sockfd, (SA*)&serveAdd, sizeof(serveAdd)) == -1) {
		ERR_EXIT("connect");
	}
	while (1) {										//死循环, 使用ctrl c信号关闭连接
		char buff[1024];
		printf("请说>>");
		scanf("%s", buff);
		write(sockfd, buff, strlen(buff));
		int n = read(sockfd, buff, sizeof(buff));
		if (n == -1) {
			ERR_EXIT("read");
		}
		buff[n] = 0;
		fprintf(stdout, ">>%s\n", buff);
	}
}

La segunda parte de la secuencia: Resolución de enlaces de blog concurrentes: https://blog.csdn.net/weixin_53695360/article/details/122790450?spm=1001.2014.3001.5502

Resumen (Este artículo tiene algunas referencias en Internet, básicamente de mi propio entendimiento, hay deficiencias, espero que todos puedan ayudar a corregir, aprender y progresar juntos)

A través de lo anterior:

Principalmente necesitamos dominar el estudio comparativo y el significado de la dirección IP de la red y la dirección MAC,

La dirección mac se establece en el campo, única en el mundo.

 La dirección IP se basa en la conexión de red. La dirección IP puede ser diferente en diferentes segmentos de red, o en el mismo segmento de red en diferentes momentos. La dirección IP se compone de número de red + número de host, que puede identificar de forma única a un host. ....

El número de puerto, debido a que es necesario distinguir diferentes procesos en el mismo host, el número de puerto es principalmente para identificar un proceso que es único para toda la red.

La esencia del servicio de conexión de socket: es la comunicación mutua basada en la red entre dos procesos diferentes en toda la red.... Este método de comunicación se denomina comunicación de socket, y su esencia es romper la limitación de comunicación entre el mismo host. y realizar la comunicación entre diferentes hosts.

Luego está el modelo TCP de la comunicación de red más básica...

A través del modelo anterior, hay ciertos problemas. Encontramos que no hay problema cuando solo un cliente se conecta al servidor, pero cuando el segundo cliente se conecta y solicita, no hay forma de atenderlo. ?

Esto no está en línea con las necesidades reales de nuestra vida, es decir, no hay forma de atender a varios clientes al mismo tiempo... Se plantea este problema, cómo resolverlo, puede discutirlo en el área de comentarios.

Supongo que te gusta

Origin blog.csdn.net/weixin_53695360/article/details/122754482
Recomendado
Clasificación