Programación del sistema Linux 67 Programación de red Transmisión de socket de 1 informe

Necesito dominar:

socket(),获取SOCKET
bind(), 绑定SOCKET到本地地址
inet_pton(), IP地址格式转换:点分式 --> 大整数
recvfrom(),用于报式套接字,从 SOCKET上接收信息
recv(), 用于流式套接字,从 SOCKET上接收信息
inet_ntop(),IP地址格式转换:大整数格式 --> 点分式格式
send(), 用于流式套接字 向SOCKET发送数据
sendto(),用于报式套接字,向SOCKET发送数据

Nota para la comunicación entre hosts:

Final pasivo (ejecutar primero, esperar a que se acceda)

1 取得SOCKET  :socket()
2 给SOCKET取得地址,即绑定本地地址(包含端口,ip等信息): bind()
3 收/发消息  :recvfrom()
4 关闭SOCKET: close()

Final activo

1 取得SOCKET
2 给SOCKET取得地址(可省略)
3 发/收消息:sendto()
4 关闭SOCKET

¿Por qué se puede omitir la operación bind () en el extremo activo, es decir, vincular la dirección local?

bind () es para obtener la dirección de SOCKET, es decir, enlazar la dirección local. Esta operación es un acuerdo con esta máquina.
Si el remitente no está de acuerdo con la dirección de esta máquina, se omite la operación bind (). Después de que el SOCKET actual se haya establecido con éxito. El sistema nos asignará una dirección libre disponible para que la usemos, y el puerto se usará para nosotros hasta el final del proceso.


enchufe()

NAME
创建通信端点,取得SOCKET
       socket - create an endpoint for communication

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

/ * Utilice un protocolo en el dominio de la familia de protocolos para completar la transmisión del tipo

Nota: Si hay uno o más protocolos en la familia de protocolos de destino que pueden admitir el tipo de transmisión de destino, entonces el protocolo de protocolo se puede escribir como 0, lo que significa que el protocolo de la familia de protocolos que admite el tipo de transmisión de destino de forma predeterminada

Por ejemplo: soccket (AF_INET, SOCK_DGRAM, 0); significa que la familia de protocolos AF_INET familia de protocolos admite el socket de protocolo de forma predeterminada para completar la transmisión del socket SOCK_DGRAM,

dominio: dominio, como el
tipo de familia de protocolo : cómo implementa la capa superior el
protocolo: protocolo
* /

   int socket(int domain, int type, int protocol);

VALOR DEVUELTO devuelve el descriptor de archivo.
En caso de éxito, se devuelve un descriptor de archivo para el nuevo conector. En caso de error, se devuelve -1 y errno se establece correctamente.

domain :
       Name                Purpose                          Man page
       AF_UNIX, AF_LOCAL   Local communication 本地协议              unix(7)
       AF_INET             IPv4 Internet protocols          ip(7)
       AF_INET6            IPv6 Internet protocols          ipv6(7)
       AF_IPX              IPX - Novell protocols
       AF_NETLINK          Kernel user interface device     netlink(7)
       AF_X25              ITU-T X.25 / ISO-8208 protocol   x25(7)
       AF_AX25             Amateur radio AX.25 protocol 无线电 短波通信
       AF_ATMPVC           Access to raw ATM PVCs
       AF_APPLETALK        AppleTalk                        ddp(7)
       AF_PACKET           Low level packet interface       packet(7)
       AF_ALG              Interface to kernel crypto API

type:

SOCK_STREAM     流式套接字,Provides sequenced, reliable, two-way, connection-based byte streams.
有序可靠:只要接收方能够接到数据,就可以保证 当前数据包中的内容是正确的。不能保证不丢包,网络传输中会有丢包
双工
基于连接:点对点,一对一
字节流传输

       SOCK_DGRAM      报式
数据分组
无连接的
不可靠的

SOCK_SEQPACKET 有序可靠的报式
有序可靠的报式

...

unir()

NAME
给SOCKET绑定一个地址
       bind - bind a name to a socket

SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

/ *
sockfd: Obtiene el descriptor de archivo devuelto por SOCKET

addr: dirección de protocolo, que depende de la información de dirección en la familia de protocolos actualmente utilizada. El tipo de dirección de protocolo en la familia de protocolos AF_INET es struct sockaddr_in

addrlen: tamaño del espacio de direcciones del protocolo

* /

   int bind(int sockfd, const struct sockaddr *addr,
            socklen_t addrlen);



sockaddr 依赖于当前用到的协议族中的地址信息 The sockaddr structure is defined as something like:

       struct sockaddr {
           sa_family_t sa_family;
           char        sa_data[14];
       }

Las diferentes familias de protocolos utilizan diferentes estructuras para vincular sus propias direcciones. Entonces no hay un tipo struct sockaddr. Entonces, nuestro método de procesamiento es: qué familia de protocolos estamos usando, usamos la dirección de la familia de protocolos como addr, y luego escribimos la longitud de la dirección en addrlen

AF_INET ver ip (7)

hombre 7 ip

/ *
Nota: La dirección IP y el puerto deben enviarse junto con la red. Representar la propia identidad
* /

           struct sockaddr_in {
				//协议族 address family: AF_INET
               sa_family_t    sin_family; 

 	   		    //需要的端口
               in_port_t      sin_port;  

//IP地址 并非点分式,而是大整数internet address ,用的时候需要格式转换:inet_pton()
               struct in_addr sin_addr;   
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order */
           };

Entonces, el tipo de dirección de protocolo en la familia de protocolos AF_INET es struct sockaddr_in

VALOR DEVUELTO
En caso de éxito, se devuelve cero. En caso de error, se devuelve -1 y errno se establece de forma adecuada.


conversión de formato de dirección IP inet_pton (): fracción de puntos -> entero grande

NAME
将  IPv4 and IPv6 addresses 转换为 二进制格式,即将点分式 转换为 二进制格式
       inet_pton - convert IPv4 and IPv6 addresses from text to binary form

SYNOPSIS
       #include <arpa/inet.h>

/ *
af: familia de protocolos, solo AF_INET o AF_INET6, a saber, IPV4 o IPV6
src: dirección IP
dst: espacio de almacenamiento después de la conversión
* /

   int inet_pton(int af, const char *src, void *dst);

0.0.0.0: puede coincidir con cualquier dirección IP, lo que significa cuál es nuestra propia dirección IP en esta etapa de vinculación, y 0.0.0.0 se reemplazará con nuestra dirección IP actual


recvfrom () Recibe información de SOCKET

NAME
从 SOCKET上接收信息
       recv, recvfrom, recvmsg - receive a message from a socket

SYNOPSIS
       #include <sys/types.h>
       #include <sys/socket.h>

/ * Se utiliza para la transmisión de toma
sockfd: TOMA objetivo
buf: recibir información de dirección de almacenamiento
len: la recepción de la información de tamaño de espacio de almacenamiento
banderas: requisitos especiales
* /

   ssize_t recv(int sockfd, void *buf, size_t len, int flags);

/ * recvfrom se usa para informar socket
sockfd: target SOCKET
buf: recibir información de dirección de almacenamiento
len: recibir información de almacenamiento de espacio de tamaño
banderas: requisitos especiales
src_addr: dirección del remitente, es decir, la dirección del extremo opuesto
addrlen: dirección del remitente tamaño del espacio, que es La dirección opuesta representa el tamaño del espacio
* /

   ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                    struct sockaddr *src_addr, socklen_t *addrlen);

recv () se aplica a los sockets de transmisión, solo es necesario especificar el socket de destino, la ubicación de la información almacenada, es decir, el tamaño y si existen requisitos especiales. Debido a que el enlace se establece de antemano, conexión uno a uno, punto a punto, por lo que no es necesario registrar quién es el extremo opuesto.

recvfrom () se utiliza para la comunicación de socket de informes. La fuente de cada mensaje recibido puede ser inconsistente, por lo que además de la necesidad de especificar el socket de destino, la ubicación y el tamaño de la información almacenada, y si existen requisitos especiales. También debe registrar quién es la otra parte, es decir, la identidad del remitente.


inet_ntop () formato de entero grande -> formato de puntos

NAME 
转换IPv4 and IPv6 addresses 地址格式, 大整数格式 --> 点分式格式
       inet_ntop - convert IPv4 and IPv6 addresses from binary to text form

SYNOPSIS
       #include <arpa/inet.h>

/ *
af: familia de protocolos
src: la dirección IP que se va a convertir
dst: cambia la IP de destino a este
tamaño de dirección : el tamaño del espacio al que apunta dst

* /

   const char *inet_ntop(int af, const void *src,
                         char *dst, socklen_t size);

enviar () 、 enviar a ()

NAME
       send, sendto, sendmsg - send a message on a socket

SYNOPSIS
       #include <sys/types.h>
       #include <sys/socket.h>

/ * Se utiliza para el socket de transmisión para enviar datos
sockfd: target SOCKET
buf: enviar información de datos dirección de almacenamiento
len: enviar información de datos tamaño del espacio de almacenamiento
* /

   ssize_t send(int sockfd, const void *buf, size_t len, int flags);

/ * Se usa para enviar datos al socket de informes
sockfd: target SOCKET
buf: enviar información de datos dirección de almacenamiento
len: enviar información de datos espacio de almacenamiento tamaño
banderas: requisitos especiales
dest_addr: dirección del receptor, es decir, la dirección del extremo opuesto
addrlen: receptor espacio de direcciones Tamaño
* /

   ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                  const struct sockaddr *dest_addr, socklen_t addrlen);

VALOR DEVUELTO
En caso de éxito, estas llamadas devuelven el número de bytes enviados. En caso de error, se devuelve -1 y errno se establece de forma adecuada.

Experimento: datos de transferencia de socket de estilo informe

proto.h

#ifndef PROTO_H_
#define PROTO_H_

#define RCVPORT "1989"
#define NAMESIZE 11
#define IPSTRSIZE 40
struct msg_st
{
	char name[NAMESIZE];
	uint32_t math;
	uint32_t chinese;
}__attribute__((pack));

#terminara si

receptor rcver.c

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include "proto.h"

int main()
{
	int sd;
	struct sockaddr_in laddr,raddr;
	struct msg_st rbuf;
	socklen_t raddr_len;
	char ipstr[IPSTRSIZE];

//取得SOCKET, 用 AF_INET协议族中 默认支持报式套接字的协议 来完成 报式SOCK_DGRAM套接字传输,
	sd = socket(AF_INET,SOCK_DGRAM,0);//IPPROTO_UDP
	if(sd < 0)
	{
		perror("soccket()");
		exit(1);
	}

//设置  AF_INET 协议族地址信息结构体,AF_INET 协议族中的 协议地址类型为 struct sockaddr_in 
 // 协议族为 AF_INET 
 laddr.sin_family = AF_INET;
// 设置端口为1989,因为需要将自己的地址信息(包括端口信息)发出去,所以需要注意字节序问题,即 从主机发向网络,htons
	laddr.sin_port = htons(atoi(RCVPORT)); 

	inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);//0.0.0.0:any address

// 给SOCKET绑定一个地址,关联到目标协议族地址信息结构体
	if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0)
	{
		perror("bind");
		exit(1);
	}

	/* !!!! *///一定要注意初始化对端地址空间大小信息
	raddr_len = sizeof(raddr);

	while(1)
	{
//以报式套接字方式 从 SOCKET上接收信息,所以需要指定对端地址信息,remote端地址信息。接收到的信息存储到rbuf
		recvfrom(sd,&rbuf,sizeof(rbuf),0,(void *)&raddr,&raddr_len);
		
// 转换IPv4 and IPv6 addresses 地址格式, 大整数格式 --> 点分式格式 存储到ipstr
		inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);

// raddr.sin_port) 是从socket接收到的信息,不是单字节信息,需要字节序转换 ntohs
		printf("---MESSAGE FROM %s:%d---\n",ipstr,ntohs(raddr.sin_port));

		printf("---NAME = %s\n",rbuf.name);//单字节信息,不需要字节序转换
		printf("---MATH = %d\n",ntohl(rbuf.math));//需要字节序转换
		printf("---CHINESE = %d\n",ntohl(rbuf.chinese));//需要字节序转换
	}	

	close(sd);

	exit(0);

}

Envío final:

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include "proto.h"

int main(int argc,char *argv[])
{
	int sd;
	struct sockaddr_in raddr;
	struct msg_st sbuf;

	if(argc < 2)
	{
		fprintf(stderr,"Usage ...\n");
		exit(1);
	}


	sd = socket(AF_INET,SOCK_DGRAM,0);//IPPROTO_UDP
	if(sd < 0)
	{
		perror("soccket()");
		exit(1);
	}

	//bind()

	strcpy(sbuf.name,"MHR");
	sbuf.math = htonl(rand()%100);
	sbuf.chinese = htonl(rand()%100);
	
	raddr.sin_family = AF_INET;
	raddr.sin_port = htons(atoi(RCVPORT));
	inet_pton(AF_INET,argv[1],&raddr.sin_addr);


	if(sendto(sd,&sbuf,sizeof(sbuf),0,(void *)&raddr,sizeof(raddr)) < 0)
	{
		perror("sendto()");
		exit(1);
	}

	puts("OK");

	close(sd);

	exit(0);

}

Se puede ver en los resultados experimentales que la transmisión de datos fue exitosa. Y debido a que no hay bind () en el extremo activo, los puertos asignados al extremo activo por el sistema de transmisión en el experimento son 45499, 56709 y 51977 respectivamente. El extremo pasivo imprime información como la información de datos del puerto IP del extremo activo.

Inserte la descripción de la imagen aquí
Ver el estado de la red

netstat -anu  //u:udp 报式套接字
netstat -ant   // t:tcp 流式套接字

mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ 
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ netstat -anu
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State      
udp        0      0 0.0.0.0:1989            0.0.0.0:*       //可以看到 1989端口 已经打开     
udp        0      0 127.0.1.1:53            0.0.0.0:*                          
udp        0      0 0.0.0.0:68              0.0.0.0:*                          
udp        0      0 0.0.0.0:631             0.0.0.0:*                          
udp        0      0 0.0.0.0:51842           0.0.0.0:*                          
udp        0      0 0.0.0.0:5353            0.0.0.0:*                          
udp6       0      0 :::59961                :::*                               
udp6       0      0 :::5353                 :::*                               
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ 


 netstat -nap |grep address number 查看程序运行的pid
如:
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ netstat -nap |grep 0.0.0.0 //代码中被动端地址 是0.0.0.0
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.1.1:53            0.0.0.0:*               LISTEN      -               
udp        0      0 0.0.0.0:1989            0.0.0.0:*                           2739/a.out    //进程IP 2739   
udp        0      0 127.0.1.1:53            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -               
udp        0      0 0.0.0.0:631             0.0.0.0:*                           -               
udp        0      0 0.0.0.0:51842           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           -               
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ kill 2739
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ netstat -nap |grep 0.0.0.0
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
tcp        0      0 127.0.1.1:53            0.0.0.0:*               LISTEN      -               
udp        0      0 127.0.1.1:53            0.0.0.0:*                           -               
udp        0      0 0.0.0.0:68              0.0.0.0:*                           -               
udp        0      0 0.0.0.0:631             0.0.0.0:*                           -               
udp        0      0 0.0.0.0:51842           0.0.0.0:*                           -               
udp        0      0 0.0.0.0:5353            0.0.0.0:*                           -               
mhr@ubuntu:~/Desktop/xitongbiancheng/socket/1$ 

Supongo que te gusta

Origin blog.csdn.net/LinuxArmbiggod/article/details/114990370
Recomendado
Clasificación