42: setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
Linux-реализация TCP, как и в остальных системах Unix, вводит ограничения на то, насколько скоро можно повторно использовать кортеж (bind()
.
Функция setsockopt()
позволяет устанавливать множество специальных опций для сокета и протокола:
#include
int setsockopt(int sock, int level, int option,
const void * valptr, int vallength);
Первый аргумент — это сокет, для которого определяется опция. Второй аргумент, level
, указывает тип устанавливаемой опции. В нашем сервере используется SOL_SOCKET
, что указывает на установку опции обобщенного сокета. Параметр option
определяет опцию, которая подлежит изменению. Указатель на новое значение опции передается через valptr
, а размер значения, на которое указывает valptr, передается как vallength
. Для нашего сервера применяется указатель на ненулевое целое число, которое вводит в действие опцию SO_REUSEADDR
.
17.5.8. Клиентские приложения TCP
Клиенты TCP подобны клиентам домена Unix. Как правило, сразу же после создания сокета, клиент подключается к серверу с помощью функции connect()
. Единственное различие состоит в способе передачи адреса в connect()
. Вместо того, чтобы использовать имя файла, большинство клиентов TCP отыскивают имя хоста через функцию getaddrinfo()
, которая предоставляет информацию для connect()
.
Ниже приводится несложный TCP-клиент, который взаимодействует с сервером, представленным в предыдущем разделе. Он принимает один аргумент: имя хоста, на котором работает сервер, или его IP-номер (в десятичном представлении с разделительными точками). Во всем остальном программа ведет себя также как клиент сокета домена Unix, показанный ранее в этой главе.
1: /* tclient.с */
2:
3: /* Подключиться к серверу, чье имя хоста или IP-адрес переданы в качестве
4: аргумента, на порте 4321. После соединения скопировать все содержимое
5: stdin в сокет, затем завершить работу. */
6:
7: #include
8: #include
9: #include
10: #include
11: #include
12: #include
13: #include
14: #include
15:
16: #include "sockutil.h" /* некоторые служебные функции */
17:
18: int main(int argc, const char ** argv) {
19: struct addrinfo hints, *addr;
20: struct sockaddr_in * addrinfo;
21: int rc;
22: int sock;
23:
24: if (argc !=2) {
25: fprintf(stderr, "поддерживается только одиночный аргумент\n");
26: return 1;
27: }
28:
29: memset(&hints, 0, sizeof(hints));
30:
31: hints.ai_socktype = SOCK_STREAM;
32: hints.ai_flags = AI_ADDRCONFIG;
33: if ((rc = getaddrinfo(argv[1], NULL, &hints, &addr))) {
34: fprintf(stderr, "сбой поиска имени хоста: %s\n",
35: gai_strerror(rc));
36: return 1;
37: }
38:
39: /* это позволяет получить доступ к sin_family и sin_port
40: (которые расположены там же, где и sin6_family и sin6_port) */
41: addrinfo = (struct sockaddr_in *) addr->ai_addr;
42:
43: if ((sock = socket(addrInfo->sin_family, addr->ai_socktype,
44: addr->ai_protocol)) < 0)
45: die("socket");
46:
47: addrInfo->sin_port = htons(4321);
48:
49: if (connect(sock, (struct sockaddr *) addrinfo,
50: addr->ai_addrlen))
51: die("connect");
52: