В строке
sock1 = socket(AF_INET, SOСK_STREAM, 0);
мы создаем наш, «серверный», сокет: набор протоколов — TCP/IP, режим — с установлением соединения.
Затем мы инициализируем структуру sin:
memset((char *)&sin, ' ', sizeof(sin));
sin.sin_family = AF_INET; // TCP/IP
sin.sin_addr.s_addr = INADDR_ANY; // можем работать на
// любом адресе
sin.sin_port = SERVER_PORT; // указываем порт (1234)
После создания сокета и инициализации структуры sin, нужно связать наш сокет с адресом и портом сервера:
bind(sock1, (struct sockaddr *)&sin, sizeof(sin));
Оператор listen(sock1, 3)
означает, что мы будем прослушивать сокет sock1 (порт 1234) и максимальное число клиентов не должно превышать 3.
Как и любой нормальный сервер, мы должны работать в бесконечном цикле, постоянно обрабатывая запросы клиентов. В бесконечном цикле мы:
1. получаем размер структуры client
ans_len = sizeof(client);
2. создаем сокет sock2, через который будем обмениваться данными с клиентом. Если в очереди listen нет клиентов, мы переходим в состояние ожидания
sock2 = accept(sock1, &client, &ans_len);
3. как только подключится клиент, мы отправим ему сообщение MSG_TO_SEND
write(sock2, MSG_TO_SEND, sizeof(MSG_TO_SEND));
4. увеличиваем счетчик клиентов
total+=1;
5. получаем размер прочитанных данных, сами данные записываются в буфер buffer
ans_len = read(sock2, buffer, BUF_SIZE);
6. выводим прочитанные данные на стандартный вывод
write(1, buffer, ans_len);
7. завершаем сеанс связи
shutdown(sock2, 0);
8. закрываем сокет
close(sock2);
Конечно, любой нормальный сервер при поступлении определенных сигналов, например, SIG_HUP, должен корректно перезапуститься или вообще завершить работу. Наш сервер этого не делает — обработку сигналов, я надеюсь, вы можете добавить сами.
Теперь мы можем откомпилировать нашу программу:
$ gcc -о server server.c
Запускаем:
./server
Программа перешла в состояние ожидания новых клиентов.
27.3.8. Программа-клиент
Программа-клиент несколько проще, чем сервер. Вот ее листинг:
Листинг 27.4. Программа-клиент
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <memory.h>
#include <stdio.h>
#define SERVER_HOST 'localhost'
#define SERVER_PORT 1234
#define CLIENT_PORT 1235
#define MSG 'Denis
'
main() {
int sock;
int ans_len;
int BUF_SIZE = 64;
char buffer[BUF_SIZE];
struct hostent *h;
struct sockaddr_in client, server;
sock = socket(AF_INET, SOCK_STREAM, 0);
memset((char *)&client, ' ', sizeof(client));
client.sin_family = AF_INET;
client.sin_addr.s_addr = INADDR_ANY;
client.sin_port = CLIENT_PORT;
bind(sock, (struct sockaddr *)&client, sizeof(client));
memset((char *)&client, ' ', sizeof(server));
h = gethostbyname(SERVER_HOST);
server.sin_family = AF_INET;
memcpy((char *)&server.sin_addr.h->h_addr, h->h_length);
server.sin_port = SERVER_PORT;
connect(sock, &server, sizeof(server));
ans_len = recv(sock, buffer, BUF_SIZE, 0);
write(1, buffer, ans_len);
send(sock, MSG, sizeof(MSG), 0);
close(sock);
exit(0);
}
Константа MSG — это сообщение, которое будет передано серверу. Как и в случае с сервером, нам понадобятся две структуры типа sockaddr_in:
struct hostent *h;
struct sockaddr_in client, server;
Структура типа hostent нам нужна для получения адреса сервера.
Создаем сокет, заполняем информацию о клиенте и связываем сокет:
sock = socket(AF_INET, SOCK_STREAM, 0);
memset((char *)&client, ' ' , sizeof(client));
client.sin_family = AF_INET;
client.sin_addr.s_addr = INADDR_ANY;
client.sin_port = CLIENT_PORT;
bind(sock, (struct sockaddr *)&client, sizeof(client));