UNIX: разработка сетевых приложений
Шрифт:
Обработка ответа
31-33
Если ответ — это сообщение T_BIND_ACK
, то связывание прошло успешно, и мы возвращаемся. Фактический адрес, связанный с точкой доступа, возвращается в элементе addr
нашей структуры bind_ack
, которую мы игнорируем.
34-39
Если ответ — это сообщение T_ERROR_ACK
, мы проверяем, было ли сообщение получено целиком, и выводим три значения, содержащиеся в возвращенной структуре. В этой простой программе при возникновении
Чтобы увидеть ошибки, которые могут возникнуть в результате запроса на связывание, мы слегка изменим нашу функцию
main
и попробуем связать какой- либо порт, отличный от 0. Например, если мы попробуем связать порт 1 (что требует прав привилегированного пользователя, так как это порт с номером меньше 1024), мы получим следующий результат:
solaris % tpi_daytime 127.0.0.1
T_ERROR_ACK from bind (3, 0)
В этой системе значение константы
EACCESS
равно 3. Если мы поменяем номер порта, задав значение большее 1023, но используемое в настоящий момент другой точкой доступа TCP, мы получим:
solaris % tpi_daytime 127.0.0.1
T_ERROR_ACK from bind (23, 0)
В данной системе значение константы
EADDRBUSY
равно 23. Следующая функция показана в листинге 31.4. Это функция
tpi_connect
, устанавливающая соединение с сервером. Листинг 31.4. Функция tpi_connect: установление соединения с сервером
//streams/tpi_connect.c
1 #include "tpi_daytime.h"
2 void
3 tpi_connect(int fd, const void *addr, size_t addrlen)
4 {
5 struct {
6 struct T_conn_req msg_hdr;
7 char addr[128];
8 } conn_req;
9 struct {
10 struct l_conn_con msg_hdr;
11 char addr[128];
12 } conn_con;
13 struct strbuf ctlbuf;
14 union T_primitives rcvbuf;
15 struct T_error_ack *error_ack;
16 struct T_discon_ind *discon_ind;
17 int flags;
18 conn_req.msg_hdr.PRIM_type = T_CONN_REQ;
19 conn_req.msg_hdr.DEST_length = addrlen;
20 conn_req.msg_hdr.DEST_offset = sizeof(struct T_conn_req);
21 conn_req.msg_hdr.OPT_length = 0;
22 conn_req.msg_hdr.OPT_offset = 0;
23 memcpy(conn_req.addr, addr, addrlen); /* sockaddr_in{} */
24 ctlbuf.len = sizeof(struct T_conn_req) + addrlen;
25 ctlbuf.buf = (char*)&conn_req;
26 Putmsg(fd, &ctlbuf, NULL, 0);
27 ctlbuf.maxlen = sizeof(union T_primitives);
28 ctlbuf.len = 0;
29 ctlbuf.buf = (char*)&rcvbuf;
30 flags = RS_HIPRI;
31 Getmsg(fd, &ctlbuf, NULL, &flags);
32 if (ctlbuf.len < (int)sizeof(long))
33 err_quit("tpi_connect: bad length from getmsg");
34 switch (rcvbuf.type) {
35 case T_OK_ACK:
36 break;
37 case T_ERROR_ACK:
38 if (ctlbuf.len < (int)sizeof(struct T_error_ack))
39 err_quit("tpi_connect: bad length for T_ERROR_ACK");
40 error_ack = (struct T_error_ack*)&rcvbuf;
41 err_quit("tpi_connect: T_ERROR_ACK from conn %d, %d)",
42 error_ack->TLI_error, error_ack->UNIX_error);
43 default:
44 err_quit("tpi connect, unexpected message type: &d", rcvbuf.type);
45 }
46 ctlbuf.maxlen = sizeof(conn_con);
47 ctlbuf.len = 0;
48 ctlbuf.buf = (char*)&conn_con;
49 flags = 0;
50 Getmsg(fd, &ctlbuf, NULL, &flags);
51 if (ctlbuf.len < (int)sizeof(long))
52 err_quit("tpi_connect2: bad length from getmsg");
53 switch (conn_con.msg_hdr.PRIM_type) {
54 case T_CONN_CON:
55 break;
56 case T_DISCON_IND:
57 if (ctlbuf.len < (int)sizeof(struct T_discon_ind))
58 err_quit("tpi_connect2: bad length for T_DISCON_IND");
59 discon_ind = (struct T_discon_ind*)&conn_con.msg_hdr;
60 err_quit("tpi_connect2: T_DISCON_IND from conn (%d)",
61 discon_ind->DISCON_reason);
62 default:
63 err_quit("tpi_connect2: unexpected message type. %d",
64 conn_con.msg_hdr PRIM_type);
65 }
66 }
Поделиться с друзьями: