Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.58.169] |
|
Сообщ.
#1
,
|
|
|
Картринка такая:
Работает сервер. К нему есть клиент. Протокол ТСП. Клиент формирует сообщения и посылает их серверу. Сервер их обрабатывает и посылает клиенту ответ. Если серверный процесс заваливается, то клиент тоже падает на функции send() (не возвращает ошибочный код завершения, а просто падает процесс) Это происходит в том случае, если размер передаваемого сообщения превышает определенный предел (около 600 байт). Если размер сообщения менее этого предела, то функция send() отрабатывает без ошибки, а следующая за ней recv() возвращает ошибочный код завершения. Повторяю: если размер сообщения увеличить, и завалить серверный процесс, то клиент просто валится без дампа ядра и вообще без каких-либо сообщений. Есть у кого-нибудь соображения по этому поводу ? |
Сообщ.
#2
,
|
|
|
То же самое под Solaris 2.6 работает нормально:
функция send() возвращает ошибочный код завершения и я его могу нормально обработать Что с 2.5.1 ? Это глюк операционки ? |
Сообщ.
#3
,
|
|
|
From : Serguei Revtov 2:5021/19.1 06 May 02 09:06:32
To : Valery Votintsev 2:5021/4.22 06 May 02 09:06:32 Subj : Solaris question ------------------------------------------------------------------------------- > rm -rf $* < VV> ошибочный код завеpшения, а пpосто падает пpоцесс) Это пpоисходит в VV> том слyчае, если pазмеp пеpедаваемого сообщения пpевышает опpеделенный VV> пpедел (около 600 байт). Если pазмеp сообщения менее этого пpедела, По-видимому это связано с pазбивкой пакета на части (не помещается в один... стpанно, эзеpнетовский около 1.5кб со всеми хедеpами, паpаметp MTU) > rm -rf $* < VV> --------- То же самое под Solaris 2.6 pаботает ноpмально: фyнкция VV> send() возвpащает ошибочный код завеpшения и я его могy VV> ноpмально обpаботать Что с 2.5.1 ? Это глюк опеpационки ? По-видимому связано с конкpетной веpсией. По идее должно бы быть пофиксено. Поискал на стаpом SunSolve CDROM, сходу нашлось следующее. Hемного похожее на описанную пpоблему. Пpавда фикса не видно. Если сильно интеpесно, можно спpосить у меня в эхе, может кто знает... Или на sunsolve.sun.com, там свежая инфоpмация. <br>=== Begin 4291038 ===<br> Bug Id: 4291038<br> Category: kernel<br> Subcategory: tcp-ip<br> State: closed<br> Synopsis: TCP does not raise OOB exception on select call if the OOB has not<br>arrived.<br> Description:<br>TCP OOB data has two parts. The first part is the URGENT bit on the TCP flags.<br>The second part is the Urgent pointer. It is possible for the urgent pointer<br>to point to a data byte that is far downstream from the current sequence<br>number.<br>This happens particularly if the data stream is stopped by flow control. In<br>this case, the pointer will point to the end of the send buffer, and will<br>be sent in a packet with no data.<br><br>The correct reponse is for TCP to deliver the notification that urgent data has<br>been sent to the process via the exception mechanism of select, but the<br>attempt to read the data via recv should return EWOULDBLOCK. Instead, the<br>exception is not raised at all.<br><br>This has been seen in 2.5.1 and before.<br><br>A test case:<br>cat rec.cc<br>#include <sys/types.h><br>#include <sys/socket.h><br>#include <netinet/in.h><br>#include <netdb.h><br>#include <stdio.h><br>#include <stdlib.h><br>#include <sys/uio.h><br>#include <unistd.h><br>#include <strings.h><br><br>#define TRUE 1<br><br>/*<br> * This program creates a socket and then begins an infinite loop. Each time<br> * through the loop accepts a connection and print out messagess from it.<br> * When the connection breaks, or a termination messages comes through, the<br> * program accepts a new connection.<br> */<br><br>main ()<br>{<br> int sock, length;<br> struct sockaddr_in server;<br> int msgsock;<br> char buf[1024];<br> int rval;<br> int i;<br><br> /* Create socket */<br> if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {<br> perror("opening stream socket");<br> exit(1);<br> }<br><br> /* Name socket using wild card */<br> bzero(&server,sizeof(server));<br> server.sin_family = AF_INET;<br> server.sin_addr.s_addr = htonl(INADDR_ANY);<br> server.sin_port = htons(9877);;<br> if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {<br> perror("binding stream socket");<br> exit(1);<br> }<br><br> /* Find out assigned port number and print it out */<br> length = sizeof server;<br> if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) {<br> perror("getting socket name");<br> exit(1);<br> }<br><br> printf ("Socket port #\%d\n", ntohs(server.sin_port));<br><br> /*<br> int sockBufSize = 120000;<br> setsockopt (sock, SOL_SOCKET, SO_RCVBUF,<br> (char*)&sockBufSize, sizeof(sockBufSize));<br> */<br><br> setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,<br> (char*)&buf, sizeof(buf));<br><br> listen(sock, 5);<br> do {<br> msgsock = accept(sock, (struct sockaddr *)0, (int *)0);<br> if (msgsock == -1)<br> perror("accept");<br> else do {<br> while (1)<br> {<br> int status;<br> fd_set exception, readmask;<br> FD_ZERO (&exception);<br> FD_ZERO (&readmask);<br> FD_SET(msgsock, &exception);<br> FD_SET(msgsock, &readmask);<br>/* status = select(msgsock+1, &readmask, NULL,<br>&exception, NULL);*/<br> status = select(msgsock+1, NULL, NULL, &exception,<br>NULL);<br> if (!FD_ISSET(msgsock, &exception))<br> {<br> static int i = 0;<br> if (((++i) \% 1024))<br> {<br> continue;<br> }<br> if ((rval = read(msgsock, buf, 1024)) < 0)<br> perror("reading stream message");<br> printf ("------> Clear \%d\n", rval);<br> sleep(1);<br> continue;<br> }<br> else<br> {<br> printf ("Got exception\n");<br> rval = recv(msgsock, buf, 1024, MSG_OOB);<br> if (rval < 0) {<br> perror("Read OOB failed");<br> exit(1);<br> }<br> if (rval == 0) {<br> printf("Hmm, got no bytes\n");<br> } else {<br> buf[rval]=0;<br> printf("Received \%d byte, OOB=\%s\n",rval,buf);<br> }<br> sleep (1);<br> }<br> }<br> memset(buf, 0, sizeof(buf));<br> if ((rval = read(msgsock, buf, 1024)) < 0)<br> perror("reading stream message");<br> i = 0;<br> if (rval == 0)<br> printf("Ending connection\n");<br> else<br> printf("-->\%s\n", buf);<br> } while (rval != 0);<br> close(msgsock);<br> } while (TRUE);<br><br> exit(0);<br>}<br><br>send.cc: cat send.cc<br>#include <sys/types.h><br>#include <sys/socket.h><br>#include <netinet/in.h><br>#include <netdb.h><br>#include <stdio.h><br>#include <stdlib.h><br>#include <sys/uio.h><br>#include <unistd.h><br>#include <arpa/inet.h><br>#include <netdb.h><br>#include <string.h><br>#include <signal.h><br>#include <fcntl.h><br>#include <errno.h><br><br>#define DATA "This is a test"<br><br>/*<br> * this program creates a socket and initiates a connection with the socket<br> * given in the command line. One message is sent over the connection and<br> * then the socket is closed, ending the connection. The form of the<br> * command line is "send_internet hostname portnumber<br> */<br><br>main (int argc, char **argv)<br>{<br> int sock;<br> long i;<br> struct sockaddr_in server;<br> struct hostent *hp;<br> char buf[100000];<br> int done;<br><br> /* Connect socket using name specified be command line */<br> server.sin_family = AF_INET;<br> hp = gethostbyname(argv[1]);<br> if (!hp) {<br> fprintf(stderr, "\%s: unknown host\n", argv[1]);<br> exit(2);<br> }<br> memcpy((char *)&server.sin_addr, (char *)hp->h_addr, hp->h_length);<br> done = 0;<br> int sockBufSize = 16384;<br> /* Create socket */<br> if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {<br> perror("opening stream socket");<br> exit(1);<br> }<br> server.sin_port = htons(9877);<br><br> if (connect(sock, (struct sockaddr *)&server, sizeof server) < 0) {<br> perror("Failed to connect to port");<br> exit(1);<br> } else {<br> printf("Connected\n");<br> }<br><br> fcntl (sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);<br> int sndsize = 0, length = 0;<br> getsockopt (sock, SOL_SOCKET, SO_SNDBUF,<br> (char*)&sndsize, &length);<br> printf ("Send size = \%d, length = \%d\n", sndsize, length);<br> sleep(5);<br><br> int j = 0;<br> int sizetosend = atoi(argv[2]);<br> int bytes = sizetosend ;<br> while (bytes == sizetosend)<br> {<br> bytes = write(sock, buf, sizetosend);<br> if (bytes == -1 )<br> printf ("write error = \%s\n", strerror(errno));<br> printf("write bytes = \%d\n", bytes);<br> j += bytes;<br> sleep(1);<br> }<br><br> printf ("Blocked after sending \%d bytes\n", j);<br> char junk;<br> int result;<br> junk = 'A';<br> printf("Sending urgent data\n");<br> result = send(sock, &junk, 1, MSG_OOB);<br> printf("Send urgent data result = \%d\n", result);<br> sleep(10);<br> exit(0);<br>}<br><br><br>Rec will listen to a port, and then send will connect to the port. Send will<br>then send data, a bit at a time, until the write fails because it would block.<br>Send then sends a byte of urgent data. A snoop shows the byte being delivered,<br>but the select never returns in the Rec program.<br><br> Work around:<br><br> Integrated in releases:<br> Duplicate of:<br> Patch id:<br> See also:<br> Summary:<br>=== End 4291038 ===<br> -- Serguei sir()cb.tver.ru || 2:5021/11.10 || 2:5021/19.1 --- GoldED+/W32 1.1.4.7 * Origin: Welcome to ru.unix.solaris (2:5021/19.1) |