我有一个小型应用程序,它使用 Unix 域套接字与客户端通信数据。 套接字的类型是 SOCK_STREAM,并且设置为阻塞模式(默认)。当客户端很懒并且无法处理我写入套接字的数据时,我在特定情况下遇到了一些麻烦 - 缓冲区趋于变满,我将阻塞 write() ,我想避免的事情。
我尝试使用 select/pselect 在 write() 之前调用它,以查看是否可以执行 write() 。事情只进行了一半,从某种意义上说,我被通知我不能再 write() (当缓冲区达到一定大小时 select 返回 0),但之后,当客户端能够再次读取时, select/pselect 不会t 通知这一点(我期望返回 1,然后我可以执行 write())。
您对此事有什么想法吗?
谢谢!
编辑:
服务器:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#define SV_SOCK_PATH "/tmp/srv_sk_stream"
#define BACKLOG 1
#define MAXWRITE 1000
#define TOMSEC 1000
int main(int argc, char* argv[]) {
struct sockaddr_un addr;
int sfd, cfd = -1;
ssize_t numRead;
char buffer[30];
int i = 0;
ssize_t retValWrite = -1;
numRead = sizeof(buffer);
if(argc !=2 ) {printf("Give the sleep value argument (msec)!\n"); return EXIT_FAILURE;}
int sleepTime = atoi(argv[1]) * TOMSEC;
fd_set writeFdSet;
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
struct timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 0;
/* create socket */
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sfd == -1) {perror("FAILED creating a socket!"); return EXIT_FAILURE;}
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT) {perror("FAILED removing old socket fd! - "); return EXIT_FAILURE;}
/* prepare it */
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path) - 1);
/* bind it */
if (bind(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) {perror("FAILED bind! - "); return EXIT_FAILURE;}
/* start to listen */
if (listen(sfd, BACKLOG) == -1) {perror("FAILED listen! - "); return EXIT_FAILURE;}
while(i<MAXWRITE) {
int bytesToRead = 0;
retValWrite = -13;
/* block in accept until a client connects (only one) */
if (-1 == cfd) {
cfd = accept(sfd, NULL, NULL);
if (cfd == -1) {perror("FAILED accept! - "); return EXIT_FAILURE;}
FD_ZERO(&writeFdSet);
FD_SET(cfd, &writeFdSet);
}
//ioctl(cfd,FIONREAD,&bytesToRead);
//printf("---------> SND_BUFF has %d bytes left to be read\n", bytesToRead);
sprintf(buffer, "PING FROM SERVER %d", i);
/* write to the client's socket */
int retValSelect = 0;
errno = 0;
retValSelect = select(cfd+1, NULL, &writeFdSet, NULL, &tv);
//perror("ERRNO from pselect: ");
if (retValSelect > 0) {
int retValFdIsSet = 0;
retValFdIsSet = FD_ISSET(cfd, &writeFdSet);
//perror("FD_ISSET - ");
if(retValFdIsSet) {
retValWrite = write(cfd, buffer, numRead);
if (retValWrite == 0 ) {
printf("Written 0 bytes\n");
} else if (retValWrite < 0) {
perror("Error writiing to socket!\n");
}
++i;
printf("Written: %d \n", i);
usleep(sleepTime);
}
} else {
printf("Wait for it... %d\n", count);
}
}
/* close client socket */
if (close(cfd) == -1) {perror("FAILED close srv socket! - "); return EXIT_FAILURE;}
if (remove(SV_SOCK_PATH) == -1 && errno != ENOENT) {perror("FAILED removing old socket fd! - "); return EXIT_FAILURE;}
return EXIT_SUCCESS;
}
客户:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#define SV_SOCK_PATH "/tmp/srv_sk_stream"
#define MAXREAD 1000
#define TOMSEC 1000
int main(int argc, char** argv)
{
struct sockaddr_un addr;
int sfd;
ssize_t numRead;
char pingStr[30];
numRead = sizeof(pingStr);
int readCount = 0;
if(argc !=2 ) {printf("Give the sleep value argument (msec)!\n"); return EXIT_FAILURE;}
int sleepTime = atoi(argv[1]) * TOMSEC;
/* create socket */
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(sfd == -1) {perror("FAILED creating a socket! - "); return EXIT_FAILURE;}
/* prepare it */
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, SV_SOCK_PATH, sizeof(addr.sun_path) - 1);
/* connect */
if (connect(sfd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1) {perror("FAILED connecting to socket! - "); return EXIT_FAILURE;}
while (readCount < MAXREAD) {
char strRead[numRead];
int bytesRead=0;
int bytesToRead=0;
ioctl(sfd,FIONREAD, &bytesToRead);
printf("---------> RCV_BUFF has %d bytes left to be read\n", bytesToRead);
/* read */
bytesRead = read(sfd, &strRead, numRead);
if(bytesRead == 0) {
perror("Read 0 bytes from socket! - ");
}
else if (bytesRead < 0) {
perror("FAILED reading from socket! - ");
}
++readCount;
printf("%d - READ: %s\n", readCount, strRead);
usleep(sleepTime);
}
/* close */
if (close(sfd) == -1) {perror("FAILED close clt socket! - "); return EXIT_FAILURE;}
return EXIT_SUCCESS;
}
服务器输出(以 100 毫秒写入)
./srvstream 100
Written: 1
Written: 2
Written: 3
Written: 4
Written: 5
Written: 6
Written: 7
Written: 8
Written: 9
Written: 10
Written: 11
Written: 12
Written: 13
Written: 14
Written: 15
Written: 16
Written: 17
Written: 18
Written: 19
Written: 20
Written: 21
Written: 22
Written: 23
Written: 24
Written: 25
Written: 26
Written: 27
Written: 28
Written: 29
Written: 30
Written: 31
Written: 32
Written: 33
Written: 34
Written: 35
Written: 36
Written: 37
Written: 38
Written: 39
Written: 40
Written: 41
Written: 42
Written: 43
Written: 44
Written: 45
Written: 46
Written: 47
Written: 48
Written: 49
Written: 50
Written: 51
Written: 52
Written: 53
Written: 54
Written: 55
Written: 56
Written: 57
Written: 58
Written: 59
Written: 60
Written: 61
Written: 62
Written: 63
Written: 64
Written: 65
Written: 66
Written: 67
Written: 68
Written: 69
Written: 70
Written: 71
Written: 72
Written: 73
Written: 74
Written: 75
Written: 76
Written: 77
Written: 78
Wait for it... 0
Wait for it... 0
Wait for it... 0
Wait for it... 0
Wait for it... 0
------->8-------- stays this way even after the client reports consumes the whole buffer
客户端(1秒读取):
./cltstream 1000
---------> RCV_BUFF has 0 bytes left to be read
1 - READ: PING FROM SERVER 0
---------> RCV_BUFF has 270 bytes left to be read
2 - READ: PING FROM SERVER 1
---------> RCV_BUFF has 540 bytes left to be read
3 - READ: PING FROM SERVER 2
---------> RCV_BUFF has 810 bytes left to be read
4 - READ: PING FROM SERVER 3
---------> RCV_BUFF has 1080 bytes left to be read
5 - READ: PING FROM SERVER 4
---------> RCV_BUFF has 1350 bytes left to be read
6 - READ: PING FROM SERVER 5
---------> RCV_BUFF has 1620 bytes left to be read
7 - READ: PING FROM SERVER 6
---------> RCV_BUFF has 1890 bytes left to be read
8 - READ: PING FROM SERVER 7
---------> RCV_BUFF has 2100 bytes left to be read
9 - READ: PING FROM SERVER 8
---------> RCV_BUFF has 2070 bytes left to be read
10 - READ: PING FROM SERVER 9
---------> RCV_BUFF has 2040 bytes left to be read
11 - READ: PING FROM SERVER 10
---------> RCV_BUFF has 2010 bytes left to be read
12 - READ: PING FROM SERVER 11
---------> RCV_BUFF has 1980 bytes left to be read
13 - READ: PING FROM SERVER 12
---------> RCV_BUFF has 1950 bytes left to be read
14 - READ: PING FROM SERVER 13
---------> RCV_BUFF has 1920 bytes left to be read
15 - READ: PING FROM SERVER 14
---------> RCV_BUFF has 1890 bytes left to be read
16 - READ: PING FROM SERVER 15
---------> RCV_BUFF has 1860 bytes left to be read
17 - READ: PING FROM SERVER 16
---------> RCV_BUFF has 1830 bytes left to be read
18 - READ: PING FROM SERVER 17
---------> RCV_BUFF has 1800 bytes left to be read
19 - READ: PING FROM SERVER 18
---------> RCV_BUFF has 1770 bytes left to be read
20 - READ: PING FROM SERVER 19
---------> RCV_BUFF has 1740 bytes left to be read
21 - READ: PING FROM SERVER 20
---------> RCV_BUFF has 1710 bytes left to be read
22 - READ: PING FROM SERVER 21
---------> RCV_BUFF has 1680 bytes left to be read
23 - READ: PING FROM SERVER 22
---------> RCV_BUFF has 1650 bytes left to be read
24 - READ: PING FROM SERVER 23
---------> RCV_BUFF has 1620 bytes left to be read
25 - READ: PING FROM SERVER 24
---------> RCV_BUFF has 1590 bytes left to be read
26 - READ: PING FROM SERVER 25
---------> RCV_BUFF has 1560 bytes left to be read
27 - READ: PING FROM SERVER 26
---------> RCV_BUFF has 1530 bytes left to be read
28 - READ: PING FROM SERVER 27
---------> RCV_BUFF has 1500 bytes left to be read
29 - READ: PING FROM SERVER 28
-----------8<------------ -- continues this way until RCV_BUFF has 0 bytes left and then blocks
最佳答案
如果处于阻塞模式,并且发送缓冲区已满,则 write() 和 send() 将不会返回 -1/EAGAIN/EWOULDBLOCK。他们会阻止。如果您想处理这些情况,您需要非阻塞模式。
关于c - 如果客户端无法应对(buffer++),如何停止写入套接字(AF_LOCAL/UNIX、SOCK_STREAM)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22891860/