socket sockaddr_in servidor que programacion por enviar ejemplos comando cliente archivos af_unix c sockets network-programming

servidor - sockaddr_in



Forma más sencilla de abrir y usar un socket en C (8)

Estoy comenzando a hacer una programación de red básica con C, y encontré todo esto sobre enchufes y todos parecen muy intrincados. Tal vez abrir sockets con C es complicado, pero me gustaría saber la forma más simple y efectiva de abrir y escribir datos en un socket en el lenguaje de programación C.

Gracias


A menos que escriba un daemon de red, la mayoría de las redes en C se pueden hacer en un nivel más alto que usando directamente los sockets, utilizando las bibliotecas apropiadas.

Por ejemplo, si solo desea recuperar un archivo con HTTP, use Neon o libcurl . Será más simple, estará en un nivel superior y tendrá SSL, IPv6, etc. gratis.



Leer y escribir desde los sockets básicos no es más difícil que leer y escribir archivos normales (solo use recv en lugar de leer y enviar en su lugar si está escrito). Las cosas se ponen trickey cuando necesitas abrir un socket. La razón de esto es porque hay muchas maneras diferentes de comunicarse utilizando sockets (TCP, UDP, etc.).


No mencionas en qué plataforma estás, pero una copia de Unix Network Programming by Stevens sería una buena adición a tu biblioteca. La mayoría de los sistemas operativos implementan los Sockets de Berkley usando socket, bind, connect, etc.


Mucho buenos consejos aquí hasta ahora. Generalmente escribo en C ++, pero puede encontrar algo de uso en un libro blanco que escribí "Cómo evitar los diez errores de programación de los mejores diez zócalos": ignore los consejos para usar el kit de herramientas de ACE (ya que requiere C ++) pero tome nota del zócalo errores en el documento: son fáciles de hacer y difíciles de encontrar, especialmente para un principiante. http://www.riverace.com/sockets10.htm


La Guía definitiva para la programación en red de Linux describe el socket fácil y explica muchas cosas como el enrutamiento del servidor, el diseño del protocolo, etc. También los zócalos TCP / IP en C, segunda edición, son buenos.


Ejemplo de TCP del servidor cliente POSIX 7

Uso

Obtenga dos computadoras en una LAN.

Ejecute el servidor en una computadora con:

./server.out

Obtenga la IP de la computadora servidor con ifconfig , por ejemplo, 192.168.0.10 .

En la otra computadora, ejecuta:

./client.out 192.168.0.10

Ahora escriba líneas en el cliente, y el servidor las devolverá incrementado en 1 (cifra ROT-1).

server.c

#define _XOPEN_SOURCE 700 #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <netdb.h> /* getprotobyname */ #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> int main(int argc, char **argv) { char buffer[BUFSIZ]; char protoname[] = "tcp"; struct protoent *protoent; int enable = 1; int i; int newline_found = 0; int server_sockfd, client_sockfd; socklen_t client_len; ssize_t nbytes_read; struct sockaddr_in client_address, server_address; unsigned short server_port = 12345u; if (argc > 1) { server_port = strtol(argv[1], NULL, 10); } protoent = getprotobyname(protoname); if (protoent == NULL) { perror("getprotobyname"); exit(EXIT_FAILURE); } server_sockfd = socket( AF_INET, SOCK_STREAM, protoent->p_proto /* 0 */ ); if (server_sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) { perror("setsockopt(SO_REUSEADDR) failed"); exit(EXIT_FAILURE); } server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl(INADDR_ANY); server_address.sin_port = htons(server_port); if (bind( server_sockfd, (struct sockaddr*)&server_address, sizeof(server_address) ) == -1 ) { perror("bind"); exit(EXIT_FAILURE); } if (listen(server_sockfd, 5) == -1) { perror("listen"); exit(EXIT_FAILURE); } fprintf(stderr, "listening on port %d/n", server_port); while (1) { client_len = sizeof(client_address); client_sockfd = accept( server_sockfd, (struct sockaddr*)&client_address, &client_len ); while ((nbytes_read = read(client_sockfd, buffer, BUFSIZ)) > 0) { printf("received:/n"); write(STDOUT_FILENO, buffer, nbytes_read); if (buffer[nbytes_read - 1] == ''/n'') newline_found; for (i = 0; i < nbytes_read - 1; i++) buffer[i]++; write(client_sockfd, buffer, nbytes_read); if (newline_found) break; } close(client_sockfd); } return EXIT_SUCCESS; }

client.c

#define _XOPEN_SOURCE 700 #include <assert.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <netdb.h> /* getprotobyname */ #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> int main(int argc, char **argv) { char buffer[BUFSIZ]; char protoname[] = "tcp"; struct protoent *protoent; char *server_hostname = "127.0.0.1"; char *user_input = NULL; in_addr_t in_addr; in_addr_t server_addr; int sockfd; size_t getline_buffer = 0; ssize_t nbytes_read, i, user_input_len; struct hostent *hostent; /* This is the struct used by INet addresses. */ struct sockaddr_in sockaddr_in; unsigned short server_port = 12345; if (argc > 1) { server_hostname = argv[1]; if (argc > 2) { server_port = strtol(argv[2], NULL, 10); } } /* Get socket. */ protoent = getprotobyname(protoname); if (protoent == NULL) { perror("getprotobyname"); exit(EXIT_FAILURE); } sockfd = socket(AF_INET, SOCK_STREAM, protoent->p_proto); if (sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } /* Prepare sockaddr_in. */ hostent = gethostbyname(server_hostname); if (hostent == NULL) { fprintf(stderr, "error: gethostbyname(/"%s/")/n", server_hostname); exit(EXIT_FAILURE); } in_addr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list))); if (in_addr == (in_addr_t)-1) { fprintf(stderr, "error: inet_addr(/"%s/")/n", *(hostent->h_addr_list)); exit(EXIT_FAILURE); } sockaddr_in.sin_addr.s_addr = in_addr; sockaddr_in.sin_family = AF_INET; sockaddr_in.sin_port = htons(server_port); /* Do the actual connection. */ if (connect(sockfd, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) == -1) { perror("connect"); return EXIT_FAILURE; } while (1) { fprintf(stderr, "enter string (empty to quit):/n"); user_input_len = getline(&user_input, &getline_buffer, stdin); if (user_input_len == -1) { perror("getline"); exit(EXIT_FAILURE); } if (user_input_len == 1) { close(sockfd); break; } if (write(sockfd, user_input, user_input_len) == -1) { perror("write"); exit(EXIT_FAILURE); } while ((nbytes_read = read(sockfd, buffer, BUFSIZ)) > 0) { write(STDOUT_FILENO, buffer, nbytes_read); if (buffer[nbytes_read - 1] == ''/n'') { fflush(stdout); break; } } } free(user_input); exit(EXIT_SUCCESS); }

En GitHub con un Makefile . Probado en Ubuntu 15.10.

Longitud del mensaje

Las llamadas de read en el cliente y el servidor se ejecutan dentro de while loops.

Al igual que cuando lee de archivos, el sistema operativo puede dividir los mensajes arbitrariamente para agilizar las cosas, por ejemplo, un paquete puede llegar mucho antes que el otro.

Entonces el protocolo debe especificar una convención de dónde se detienen los mensajes. Los métodos comunes incluyen:

  • un encabezado con un indicador de longitud (por ejemplo, HTTP Content-Length )
  • una cadena única que termina los mensajes. Aquí usamos /n .
  • el servidor cierra la conexión: HTTP permite que https://.com/a/25586633/895245 . Limitado, por supuesto, ya que el siguiente mensaje requiere una reconexión.

Próximos pasos

Este ejemplo es limitado porque:

  • el servidor solo puede manejar una conexión de cliente a la vez
  • la comunicación se sincroniza simplemente. Por ejemplo: en una aplicación de chat P2P, el servidor (otra persona) podría enviar mensajes en cualquier momento.

La resolución de esos problemas requiere el enhebrado y posiblemente otras llamadas como la poll .


Tienes razón, usar enchufes en C tiene una sintaxis difícil. Los lenguajes posteriores, como Java y Python, lo convierten en un complemento en comparación. El mejor tutorial que he encontrado para hacer la programación de socket en C es la Guía de programación de red de Beej . Le recomiendo que empiece desde el principio para obtener una buena descripción general, pero si solo necesita obtener algún código que funcione ahora , puede pasar directamente a la sección titulada Antecedentes Cliente-Servidor .

¡Buena suerte!