Acerca del enchufe

-- win API socket

A menos que se especifique lo contrario, las funciones de Socket mencionadas en este artículo se refieren a la API de Windows Socket.

1. Función WSAStartup

int WSAStartup(

WORD wVersionRequested,

LPWSADATA lpWSAData

);

Los programas que usan Socket deben llamar a la función WSAStartup antes de usar Socket. El primer parámetro de esta función indica la versión de Socket solicitada por el programa, donde el byte de orden superior indica la versión menor y el byte de orden inferior indica la versión principal. El sistema operativo utiliza el segundo parámetro para devolver la información de la versión de Socket solicitada; . Cuando una aplicación llama a la función WSAStartup, el sistema operativo busca la biblioteca de Socket correspondiente según la versión de Socket solicitada y luego vincula la biblioteca de Socket encontrada a la aplicación. Luego, la aplicación puede llamar a otras funciones de Socket en la biblioteca de Socket solicitada. Esta función devuelve 0 después de una ejecución exitosa.

Ejemplo: Si un programa quiere utilizar la versión 2.1 de Socket, el código del programa es el siguiente

wVersionRequested = MAKEWORD( 2, 1 );

err = WSAStartup( wVersionRequested, &wsaData );

2. Función WSACleanup

int WSACleanup (void);

Después de que la aplicación complete el uso de la biblioteca de Socket solicitada , debe Llame a la función WSACleanup para desvincular la biblioteca de Socket y liberar los recursos del sistema ocupados por la biblioteca de Socket.

3. Función de socket

Socket SOCKET(

int af,

tipo int,

protocolo int

);

La aplicación llama a la función socket para crear un socket capaz de comunicarse en red. El primer parámetro especifica la familia de protocolos de comunicación utilizada por la aplicación. Para la familia de protocolos TCP/IP, este parámetro se establece en PF_INET; el segundo parámetro especifica el tipo de socket que se creará. El tipo de socket es SOCK_DGRAM; el tercer parámetro especifica el protocolo de comunicación utilizado por la aplicación. Esta función devuelve el descriptor del socket recién creado si la llamada es exitosa, o INVALID_SOCKET si falla. Un descriptor de socket es un valor entero. Hay una tabla de descriptores de socket en el espacio de proceso de cada proceso, que almacena la relación correspondiente entre el descriptor de socket y la estructura de datos del socket. Hay un campo en esta tabla que almacena el descriptor del socket recién creado y otro campo almacena la dirección de la estructura de datos del socket, por lo que la estructura de datos del socket correspondiente se puede encontrar en función del descriptor del socket. Cada proceso tiene una tabla de descriptores de socket en su propio espacio de proceso, pero las estructuras de datos del socket están en el búfer del kernel del sistema operativo. El siguiente es un ejemplo de creación de un socket de flujo:

struct protoent *ppe;

ppe=getprotobyname("tcp");

SOCKET ListenSocket=socket (PF_INET,SOCK_STREAM,ppe->p_proto);

4. función closesocket

int closesocket(

SOCKET s

);

La función closesocket se utiliza para cerrar un descriptor del socket s. Dado que hay una tabla de descriptores de socket en cada proceso, cada descriptor de socket en la tabla corresponde a una estructura de datos de socket ubicada en el búfer del sistema operativo, por lo que puede haber varios sockets. La palabra descriptor apunta a la misma estructura de datos de socket. Hay un campo especial en la estructura de datos del socket para almacenar el número de referencias a la estructura, es decir, cuántos descriptores de socket apuntan a la estructura. Al llamar a la función closesocket, el sistema operativo primero verifica el valor de este campo en la estructura de datos del socket. Si es 1, significa que solo hay un descriptor de socket que apunta a él, por lo que el sistema operativo primero coloca s en el socket. descripción Se borra la entrada correspondiente en la tabla de descriptores y se libera la estructura de datos del socket correspondiente a s. Si este campo es mayor que 1, el sistema operativo solo borra la entrada correspondiente de s en la tabla de descriptores de socket. s El número de referencias a la estructura de datos del socket correspondiente se reduce en 1.

La función closesocket devuelve 0 si se ejecuta correctamente; de ​​lo contrario, devuelve SOCKET_ERROR.

5. función de envío

int send(

SOCKET s,

const char FAR *buf,

int len,

int flags

);

Tanto las aplicaciones cliente como las de servidor utilizan la función de envío para enviar datos al otro extremo de la conexión TCP. El programa cliente generalmente usa la función de envío para enviar una solicitud al servidor, y el servidor generalmente usa la función de envío para enviar una respuesta al programa cliente. El primer parámetro de esta función especifica el descriptor del socket de envío; el segundo parámetro especifica un búfer para almacenar los datos que enviará la aplicación; el tercer parámetro especifica el número real de bytes de datos que se enviarán; establecido en 0. Aquí solo se describe el proceso de ejecución de la función de envío del Socket síncrono. Al llamar a esta función, enviar primero compara la longitud len de los datos que se enviarán con la longitud del búfer de envío del socket s. Si len es mayor que la longitud del búfer de envío de s, la función devuelve SOCKET_ERROR si len es. menor o igual a s. La longitud del búfer de envío, luego enviar primero verifica si el protocolo está enviando los datos en el búfer de envío de s. Si es así, espera a que el protocolo termine de enviar los datos. aún no ha comenzado a enviar los datos en el búfer de envío de s o en el búfer de envío de s. No hay datos en s, entonces enviar compara el espacio restante del búfer de envío de s con len. Si len es mayor que el tamaño del espacio restante, envía. esperará a que el protocolo termine de enviar los datos en el búfer de envío de s. Si len es menor que el tamaño del espacio restante, enviar simplemente copiará los datos en buf al espacio restante (tenga en cuenta que enviar no transfiere los datos en el búfer de envío). de s al otro extremo de la conexión, pero el protocolo. Send solo copia los datos en buf al búfer de envío de s (el espacio restante en el búfer). Si la función de envío copia los datos correctamente, devuelve el número real de bytes copiados. Si se produce un error cuando el envío copia los datos, el envío devuelve SOCKET_ERROR. Si la red se desconecta mientras el envío está esperando que el protocolo transmita los datos, el La función de envío también devuelve SOCKET_ERROR. Cabe señalar que la función de envío regresa después de copiar con éxito los datos en buf al espacio restante del búfer de envío de s, pero en este momento los datos no necesariamente se transfieren inmediatamente al otro extremo de la conexión. Si ocurre un error de red durante la transmisión posterior del protocolo, la siguiente función de Socket devolverá SOCKET_ERROR. (Cada función de Socket, excepto enviar, siempre espera a que el protocolo transmita los datos en el búfer de envío del socket al comienzo de la ejecución. Si se produce un error de red mientras se espera, la función de Socket devolverá SOCKET_ERROR)

Nota: En los sistemas Unix, si la red se desconecta mientras el envío espera que el protocolo transmita datos, el proceso que llama al envío recibirá una señal SIGPIPE y el procesamiento predeterminado de la señal por parte del proceso es la terminación del proceso.

6. función recv

int recv(

SOCKET s,

char FAR *buf,

int len,

int flags

);

Tanto las aplicaciones cliente como las de servidor utilizan la función recv para recibir datos del otro extremo de la conexión TCP. El primer parámetro de esta función especifica el descriptor del socket de recepción; el segundo parámetro especifica un búfer, que se utiliza para almacenar los datos recibidos por la función recv; el tercer parámetro especifica la longitud de buf; el cuarto parámetro generalmente se establece en 0; . Aquí solo se describe el proceso de ejecución de la función recv de sincronización de Socket. Cuando la aplicación llama a la función recv, recv primero espera a que el protocolo transmita los datos en el búfer de envío de s. Si se produce un error de red cuando el protocolo transmite los datos en el búfer de envío de s, la función recv regresa. SOCKET_ERROR Si el búfer de envío de s no hay datos en el socket o los datos se envían correctamente mediante el protocolo, recv primero verifica el búfer de recepción del socket s si no hay datos en el búfer de recepción de s o el protocolo. está recibiendo datos, entonces recv esperará hasta que el protocolo reciba los datos completos. Cuando el protocolo completa la recepción de los datos, la función recv copia los datos en el búfer de recepción de s a buf (tenga en cuenta que los datos recibidos por el protocolo pueden ser mayores que la longitud de buf, por lo que en este caso, la función recv debe se llamará varias veces para copiar s Los datos en el búfer de recepción se copian (la función recv solo copia los datos, los datos de recepción reales los completa el protocolo) y la función recv devuelve el número real de bytes copiados. Si recv comete un error al copiar, devuelve SOCKET_ERROR; si la función recv se interrumpe mientras espera que el protocolo reciba datos, devuelve 0.

Nota: En sistemas Unix, si la red se desconecta mientras la función recv está esperando que el protocolo reciba datos, el proceso que llama a recv recibirá una señal SIGPIPE. El procesamiento predeterminado de la señal por parte del proceso. es la terminación del proceso.

7. función de enlace

int bind(

SOCKET s,

const struct sockaddr FAR *name,

int namelen

);

Cuando se crea un socket, hay una dirección IP predeterminada y un número de puerto predeterminado en la estructura de datos del socket. Un programa de servicio debe llamar a la función de vinculación para vincularla a una dirección IP y un número de puerto específico. Los programas cliente generalmente no necesitan llamar a la función de vinculación para vincular la dirección IP y el número de puerto de su socket. El primer parámetro de esta función especifica el descriptor de Socket que se vinculará; el segundo parámetro especifica una estructura sockaddr, que se define de la siguiente manera:

struct sockaddr {

u_short sa_family

char sa_data[14];

};

sa_family especifica la familia de direcciones. Para el socket de la familia de protocolos TCP/IP, configúrelo AF_INET. Al vincular un socket en la familia de protocolos TCP/IP, generalmente usamos otra estructura de dirección:

struct sockaddr_in {

short sin_family;

u_short sin_port;

struct in_addr sin_addr;

char sin_zero[8];

};

donde sin_family está configurado en AF_INET sin_port Especifique el puerto; número; solo hay un campo único s_addr en la estructura sin_addr, que representa la dirección IP. Este campo es un número entero. Generalmente, la función inet_addr() se usa para convertir la dirección IP en forma de cadena en una cadena larga sin signo. valor entero y luego configúrelo en s_addr. Algunos servidores son multitarjeta y tienen al menos dos tarjetas de red. Luego, el programa de servicio que se ejecuta en dicho servidor puede configurar htonl(INADDR_ANY) en s_addr al vincular la dirección IP de su socket. La ventaja de esto es que no importa cuál sea. los programas cliente en el segmento de red pueden comunicarse con el programa de servicio si solo vincula una dirección IP fija al socket del programa de servicio que se ejecuta en la máquina multihost, entonces solo los programas cliente en el mismo segmento de red que la dirección IP; Solo el programa cliente puede comunicarse con el programa de servicio. Llenamos la matriz sin_zero con 0 para que el tamaño de la estructura sockaddr_in sea consistente con el tamaño de la estructura sockaddr. El siguiente es un ejemplo de una llamada de función de enlace:

struct sockaddr_in saddr;

saddr.sin_family = AF_INET;

saddr.sin_port = htons(8888) ;

saddr.sin_addr.s_addr = htonl(INADDR_ANY);

bind(ListenSocket,(struct sockaddr *)&saddr,sizeof(saddr));

8. función de escucha

int listening(SOCKET s, int backlog);

El programa de servicio puede llamar a la función de escucha para poner sus sockets de flujo en estado de escucha. Los sockets de flujo en el estado de escucha mantendrán una cola de solicitudes de conexión de clientes, que puede acomodar hasta solicitudes de conexión de clientes pendientes. Si la función se ejecuta correctamente, devuelve 0; si falla, devuelve SOCKET_ERROR.

9. aceptar función

SOCKET aceptar(

SOCKET s,

struct sockaddr FAR *addr,

int FAR *addrlen

);

El programa de servicio llama a la función de aceptación para recuperar la solicitud principal del cliente de la cola de solicitudes de conexión del cliente de los sockets de flujo en el estado de escucha. Y cree un nuevo socket para crear un canal de conexión con el socket del cliente. Si la conexión es exitosa, se devuelve el descriptor del socket recién creado. El socket recién creado se utilizará para intercambiar datos con el socket del cliente en el futuro. palabra; si falla, devuelve INVALID_SOCKET.

El primer parámetro de esta función especifica el socket de flujo en el estado de escucha; el sistema operativo usa el segundo parámetro para devolver la estructura de dirección del socket recién creado; el sistema operativo usa el tercer parámetro para devolver la longitud del socket recién creado; estructura de dirección de palabra. El siguiente es un ejemplo de llamada a aceptar:

struct sockaddr_in ServerSocketAddr;

int addrlen;

addrlen=sizeof(ServerSocketAddr);

ServerSocket=accept(ListenSocket,(struct sockaddr *)&ServerSocketAddr,&addrlen);

10. función de conexión

int connect(

SOCKET s,

const struct sockaddr FAR *name,

int namelen

);

El programa cliente llama a la función de conexión para conectar los sockets del cliente. al nombre del oyente Conéctese al servicio Socket en un puerto específico de la computadora especificada. Si la conexión es exitosa, connect devuelve 0; si falla, devuelve SOCKET_ERROR.

Aquí hay un ejemplo:

struct sockaddr_in daddr;

memset((void *)&daddr,0,sizeof(daddr));

daddr.sin_family= AF_INET;

daddr.sin_port=htons(8888);

daddr.sin_addr.s_addr=inet_addr("133.197.22.4");

conectar(ClientSocket ,(struct sockaddr *)&daddr,sizeof(daddr));