Чтобы сделать процесс сервером TCP, вам нужно выполнить шаги, приведенные ниже —
-
Создайте сокет с помощью системного вызова socket () .
-
Свяжите сокет с адресом, используя системный вызов bind () . Для сокета сервера в Интернете адрес состоит из номера порта на хост-компьютере.
-
Прослушайте соединения с помощью системного вызова listen () .
-
Принять соединение с помощью системного вызова accept () . Этот вызов обычно блокируется, пока клиент не соединится с сервером.
-
Отправка и получение данных с использованием системных вызовов read () и write () .
Создайте сокет с помощью системного вызова socket () .
Свяжите сокет с адресом, используя системный вызов bind () . Для сокета сервера в Интернете адрес состоит из номера порта на хост-компьютере.
Прослушайте соединения с помощью системного вызова listen () .
Принять соединение с помощью системного вызова accept () . Этот вызов обычно блокируется, пока клиент не соединится с сервером.
Отправка и получение данных с использованием системных вызовов read () и write () .
Теперь давайте поместим эти шаги в виде исходного кода. Поместите этот код в файл server.c и скомпилируйте его с помощью компилятора gcc .
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here process will * go in sleep mode and will wait for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); /* Accept actual connection from the client */ newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* If connection is established then start communicating */ bzero(buffer,256); n = read( newsockfd,buffer,255 ); if (n < 0) { perror("ERROR reading from socket"); exit(1); } printf("Here is the message: %s\n",buffer); /* Write a response to the client */ n = write(newsockfd,"I got your message",18); if (n < 0) { perror("ERROR writing to socket"); exit(1); } return 0; }
Обработка нескольких соединений
Чтобы позволить серверу обрабатывать несколько одновременных соединений, мы вносим следующие изменения в приведенный выше код:
-
Поместите оператор accept и следующий код в бесконечный цикл.
-
После того, как соединение установлено, вызовите fork (), чтобы создать новый процесс.
-
Дочерний процесс закроет sockfd и вызовет функцию допроцессинга , передав в качестве аргумента новый дескриптор файла сокета. Когда два процесса завершили свой диалог, на что указывает возвращение doprocessing () , этот процесс просто завершается.
-
Родительский процесс закрывает newsockfd . Поскольку весь этот код находится в бесконечном цикле, он вернется к оператору accept для ожидания следующего соединения.
Поместите оператор accept и следующий код в бесконечный цикл.
После того, как соединение установлено, вызовите fork (), чтобы создать новый процесс.
Дочерний процесс закроет sockfd и вызовет функцию допроцессинга , передав в качестве аргумента новый дескриптор файла сокета. Когда два процесса завершили свой диалог, на что указывает возвращение doprocessing () , этот процесс просто завершается.
Родительский процесс закрывает newsockfd . Поскольку весь этот код находится в бесконечном цикле, он вернется к оператору accept для ожидания следующего соединения.
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/in.h> #include <string.h> void doprocessing (int sock); int main( int argc, char *argv[] ) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n, pid; /* First call to socket() function */ sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("ERROR opening socket"); exit(1); } /* Initialize socket structure */ bzero((char *) &serv_addr, sizeof(serv_addr)); portno = 5001; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); /* Now bind the host address using bind() call.*/ if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { perror("ERROR on binding"); exit(1); } /* Now start listening for the clients, here * process will go in sleep mode and will wait * for the incoming connection */ listen(sockfd,5); clilen = sizeof(cli_addr); while (1) { newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) { perror("ERROR on accept"); exit(1); } /* Create child process */ pid = fork(); if (pid < 0) { perror("ERROR on fork"); exit(1); } if (pid == 0) { /* This is the client process */ close(sockfd); doprocessing(newsockfd); exit(0); } else { close(newsockfd); } } /* end of while */ }
Следующий фрагмент кода показывает простую реализацию функции обработки данных.