int len;
struct sockaddr_un address;
int result;
char ch = 'A';
2. Создайте сокет для клиента:
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
3. Назовите сокет по согласованию с сервером:
address.sun_family = AF_UNIX;
strcpy(address.sun_path, "server_socket");
len = sizeof(address);
4. Соедините ваш сокет с сокетом сервера:
result = connect(sockfd, (struct sockaddr *)&address, len);
if (result == -1) {
perror("oops : client1");
exit(1);
}
5. Теперь вы можете читать и писать через sockfd:
write(sockfd, &ch, 1);
read(sockfd, &ch, 1);
printf("char from server = %c\n", ch);
close(sockfd);
exit(0);
}
Эта программа завершится аварийно, если вы попытаетесь выполнить ее, потому что еще не создан именованный сокет сервера, (Точное сообщение об ошибке может отличаться в разных системах.)
$ ./client1
oops: client1: No such file or directory
$
Далее приведена программа простого сервера server1.с, которая принимает запрос на соединение от клиента. Она создает сокет сервера, присваивает ему имя, создает очередь ожидания и принимает запросы на соединения.
1. Включите необходимые заголовочные файлы и задайте переменные:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
int server_sockfd, client_sockfd;
int server_len, client_len;
struct sockaddr_un server_address;
struct sockaddr_un client_address;
2. Удалите все старые сокеты и создайте неименованный сокет для сервера:
unlink("server_socket");
server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
3. Присвойте имя сокету:
server_address.sun_family = AF_UNIX;
strcpy(server_address.sun_path, "server_socket");
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
4. Создайте очередь запросов на соединение и ждите запроса клиента:
listen(server_sockfd, 5);
while(1) {
char ch;
printf("server waiting\n");
5. Примите запрос на соединение:
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
6. Читайте и записывайте данные клиента с помощью client_sockfd:
read(client_sockfd, &ch, 1);
ch++;
write(client_sockfd, &ch, 1);
close(client_sockfd);
}
}
Как это работает
В этом примере серверная программа в каждый момент времени может обслуживать только одного клиента. Она просто читает символ, поступивший от клиента, увеличивает его и записывает обратно. В более сложных системах, где сервер должен выполнять больше работы по поручению клиента, такой подход будет неприемлемым, потому что другие клиенты не смогут подключиться до тех пор, пока сервер не завершит работу. Позже вы увидите пару методов, позволяющих подключаться многочисленным клиентам.
Когда вы выполняете серверную программу, она создает сокет и ждет запросов на соединение. Если вы запустите ее в фоновом режиме, т.е. она будет выполняться независимо, вы сможете затем запускать клиентов как высокоприоритетные задачи.
$ ./server1 &
[1] 1094
$ server waiting
Ожидая запросы на соединения, сервер выводит сообщение. В приведенном примере сервер ждет запрос с сокета файловой системы, и вы сможете увидеть его с помощью обычной команды ls.
Хорошо взять за правило удалять сокет после окончания работы с ним, даже в случае аварийного завершения программы из-за получения сигнала. Это убережет файловую систему от загромождения неиспользуемыми файлами.
$ ls -lF server socket
srwxr-xr-x 1 neil users 0 2007-06-23 11:41 server_socket=
Здесь тип устройства — сокет, на что указывает символ s перед правами доступа и символ = в конце имени. Сокет был создан как обычный файл с правами доступа, модифицированными текущей umask. Если применить команду ps, то можно увидеть сервер, выполняющийся в фоновом режиме. Он показан спящим (параметр STAT равен s) и, следовательно, не потребляющим ресурсы ЦП.
$ ps lх
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 23385 10689 17 0 1424 312 361800 S pts/1 0:00 ./server1
Теперь, когда вы запустите программу, то успешно подключитесь к серверу. Поскольку сокет сервера существует, вы можете соединиться с ним и обмениваться данными.
$ ./client1
server waiting char from server = В
$
На терминале вывод сервера и клиента перемешаны, но можно увидеть, что сервер получил символ от клиента, увеличил его и вернул. Далее сервер продолжает выполняться и ждет следующего клиента. Если вы запустите несколько клиентов вместе, они будут обслуживаться по очереди, хотя полученный вывод может оказаться еще более перемешанным.
$ ./client1 & ./client1 & ./client1 &