4.14резюме: общая схема работы с сокетами.Мы рассмотрели все основные функции работы с сокетами. Обобщая изложенное, можно изобразить общую схему работы с сокетами с установлением соединения в следующем виде: Рис. 20 Схема работы с сокетами с установлением соединения Общая схема работы с сокетами без предварительного установления соединения проще, она такова: Рис. 21 Схема работы с сокетами без установления соединения Работа с локальными сокетами. Рассмотрим небольшой пример, иллюстрирующий работу с сокетами в рамках локального домена (AF_UNIX). Ниже приведена небольшая программа, которая в зависимости от параметра командной строки исполняет роль клиента или сервера. Клиент и сервер устанавливают соединение с использованием датаграммных сокетов. Клиент читает строку со стандартного ввода и пересылает серверу; сервер посылает ответ в зависимости от того, какова была строка. При введении строки «quit» и клиент, и сервер завершаются. #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <stdio.h> #include <string.h>
#define SADDRESS "mysocket" #define CADDRESS "clientsocket" #define BUFLEN 40 int main(int argc, char **argv) { struct sockaddr_un party_addr, own_addr; int sockfd; int is_server; char buf[BUFLEN]; int party_len; int quitting;
if (argc != 2) { printf("Usage: \%s client|server. ", argv[0]); return 0; } quitting = 1;
/* определяем, кто мы: клиент или сервер*/ is_server = !strcmp(argv[1], "server"); memset(&own_addr, 0, sizeof(own_addr)); own_addr.sun_family = AF_UNIX; strcpy(own_addr.sun_path, is_server ? SADDRESS : CADDRESS);
/* создаем сокет */ if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { printf("can't create socket "); return 0; }
/* связываем сокет */ unlink(own_addr.sun_path); if (bind(sockfd, (struct sockaddr *) &own_addr, sizeof(own_addr.sun_family)+ strlen(own_addr.sun_path)) < 0) { printf("can't bind socket!"); return 0; }
if (!is_server) { /* это – клиент */ memset(&party_addr, 0, sizeof(party_addr)); party_addr.sun_family = AF_UNIX; strcpy(party_addr.sun_path, SADDRESS); printf("type the string: ");
while (gets(buf)) { /* не пора ли выходить? */ quitting = (!strcmp(buf, "quit"));
/* считали строку и передаем ее серверу */ if (sendto(sockfd, buf, strlen(buf) + 1, 0, (struct sockaddr *) &party_addr, sizeof(party_addr.sun_family) + strlen(SADDRESS)) != strlen(buf) + 1) { printf("client: error writing socket! "); return 0; }
/*получаем ответ и выводим его на печать*/ if (recvfrom(sockfd, buf, BUFLEN, 0, NULL, 0) < 0) { printf("client: error reading socket! "); return 0; } printf("client: server answered: \%s ", buf); if (quitting) break; printf("type the string: "); } // while close(sockfd); return 0; } // if (!is_server)
/* это – сервер */ while (1) { /* получаем строку от клиента и выводим на печать */ party_len = sizeof(party_addr); if (recvfrom(sockfd, buf, BUFLEN, 0,(struct sockaddr *) &party_addr, &party_len) < 0) { printf("server: error reading socket!"); return 0; }
printf("server: received from client: \%s ", buf); /* не пора ли выходить? */ quitting = (!strcmp(buf, "quit")); if (quitting) strcpy(buf, "quitting now!"); else if (!strcmp(buf, "ping!")) strcpy(buf, "pong!"); else strcpy(buf, "wrong string!"); /* посылаем ответ */ if (sendto(sockfd, buf, strlen(buf) + 1, 0, (struct sockaddr *) &party_addr, party_len) != strlen(buf)+1) { printf("server: error writing socket! "); return 0; } if (quitting) break; } // while close(sockfd); return 0; } Пример работы с сокетами в рамках сети. В качестве примера работы с сокетами в домене AF_INET напишем простенький web-сервер, который будет понимать только одну команду : GET /<имя файла> Сервер запрашивает у системы сокет, связывает его с адресом, считающимся известным, и начинает принимать клиентские запросы. Для обработки каждого запроса порождается отдельный потомок, в то время как родительский процесс продолжает прослушивать сокет. Потомок разбирает текст запроса и отсылает клиенту либо содержимое требуемого файла, либо диагностику (“плохой запрос” или “файл не найден”). #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <netinet/in.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h>
#define PORTNUM 8080 #define BACKLOG 5 #define BUFLEN 80
#define FNFSTR "404 Error File Not Found " #define BRSTR "Bad Request "
int main(int argc, char **argv) { struct sockaddr_in own_addr, party_addr; int sockfd, newsockfd, filefd; int party_len; char buf[BUFLEN]; int len; int i; /* создаем сокет */ if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("can't create socket "); return 0; } /* связываем сокет */ memset(&own_addr, 0, sizeof(own_addr)); own_addr.sin_family = AF_INET; own_addr.sin_addr.s_addr = INADDR_ANY; own_addr.sin_port = htons(PORTNUM); if (bind(sockfd, (struct sockaddr *) &own_addr, sizeof(own_addr)) < 0) { printf("can't bind socket!"); return 0; }
/* начинаем обработку запросов на соединение */ if (listen(sockfd, BACKLOG) < 0) { printf("can't listen socket!"); return 0; }
while (1) { memset(&party_addr, 0, sizeof(party_addr)); party_len = sizeof(party_addr); /* создаем соединение */ if ((newsockfd = accept(sockfd, (struct sockaddr *)&party_addr, &party_len)) < 0) { printf("error accepting connection!"); return 0; }
if (!fork()) { /*это – сын, он обрабатывает запрос и посылает ответ*/ close(sockfd); /* этот сокет сыну не нужен */ if ((len = recv(newsockfd, &buf, BUFLEN, 0)) < 0) { printf("error reading socket!"); return 0; } /* разбираем текст запроса */ printf("received: \%s ", buf); if (strncmp(buf, "GET /", 5)) { /*плохой запрос!*/ if (send(newsockfd, BRSTR, strlen(BRSTR) + 1, 0) != strlen(BRSTR) + 1) { printf("error writing socket!"); return 0; }
shutdown(newsockfd, 1); close(newsockfd); return 0; }
for (i=5; buf[i] && (buf[i] > ' '); i++); buf[i] = 0; /* открываем файл */ if ((filefd = open(buf+5, O_RDONLY)) < 0) { /* нет файла! */ if (send(newsockfd, FNFSTR, strlen(FNFSTR) + 1, 0) != strlen(FNFSTR) + 1) { printf("error writing socket!"); return 0; } shutdown(newsockfd, 1); close(newsockfd); return 0; }
/* читаем из файла порции данных и посылаем их клиенту */ while (len = read(filefd, &buf, BUFLEN)) if (send(newsockfd, buf, len, 0) < 0) { printf("error writing socket!"); return 0; } close(filefd); shutdown(newsockfd, 1); close(newsockfd); return 0; }
/* процесс – отец. Он закрывает новый сокет и продолжает прослушивать старый */ close(newsockfd); } }
|
|