c-Linux套接字:second read()在本地主机上失败



我有一个服务器,它确认一个命令,然后发送数据。它与命令行配合良好:echo "show version" | nc -q1 127.0.0.1 5000给出:

Command received: show version
Beta

我有一个客户端,它的行为应该与命令行测试完全相同,但它挂起在第二个read()调用上,除非我在不同的服务器上运行它。我在unix域套接字方面也遇到过同样的问题,只是它们偶尔会工作。

为什么它只在本地主机上失败?

客户端来源

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define ERR_FAIL_CONNECT        -1
#define ERR_SOCK_SELECT         -2
#define ERR_SOCK_READ           -3
#define ERR_SOCK_WRITE          -3
#define ERR_SOCK_REMOTE_CLOSED  -4
int tcpConnect (char *ipAddr, int port);
int sendCommand (char *buf, int bufSize);
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout);
int main() {
char buf[64];
int nBytes;
strcpy(buf, "show version");
nBytes = sendCommand(buf, sizeof(buf));
printf("Response: %sn", buf);
return 0;
}
int sendCommand (char *buf, int bufSize) {
int apiSock;
int nBytes = ERR_SOCK_SELECT;
int len;
struct timeval timeout;
apiSock = tcpConnect("127.0.0.1", 5000);
if (!apiSock) return ERR_FAIL_CONNECT;
len = strlen(buf);
nBytes = write(apiSock, buf, len);
if (nBytes < 0) {
perror("ERROR writing to socket");
nBytes = ERR_SOCK_WRITE;
}
else if (nBytes < len) {
fprintf(stderr, "Command truncated at %d/%dn", nBytes, len);
nBytes = ERR_SOCK_WRITE;
}
else {
timeout.tv_sec = 3;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
if (nBytes > 0) {
timeout.tv_sec = 20;
timeout.tv_usec = 0;
nBytes = readWithTimeout(apiSock, buf, bufSize, &timeout);
}
}
close(apiSock);
return nBytes;
}
int tcpConnect (char *ipAddr, int port) {
struct sockaddr_in addr;
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1) {
perror("ERROR: Could not create TCP socket");
return 0;
}
addr.sin_addr.s_addr = inet_addr(ipAddr);
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
perror("ERROR: Could not connect");
return 0;
}
return sock;
}
int readWithTimeout (int sock, char *buf, int bufSize, struct timeval *timeout) {
int res;
int nBytes = ERR_SOCK_SELECT;
fd_set set;
fprintf(stderr, "readWithTimeout(sock=%d, buf='%s', bufSize=%d, timeout{tv_sec=%d, tv_usec=%d})n",
sock, buf, bufSize, timeout->tv_sec, timeout->tv_usec);
FD_ZERO(&set);
FD_SET(sock, &set);
res = select(sock+1, &set, NULL, NULL, timeout);
if (res < 0) perror("ERROR waiting for data");
else if (res == 0) fprintf(stderr, "Timed out waiting for datan");
else {
nBytes = read(sock, buf, bufSize);
if (nBytes < 0) {
perror("ERROR reading from socket");
nBytes = ERR_SOCK_READ;
}
else if (nBytes == 0) {
fprintf(stderr, "Remote end closed socketn");
shutdown(sock, 2);
close(sock);
nBytes = ERR_SOCK_REMOTE_CLOSED;
}
}
return nBytes;
}

服务器源

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define TCP_PORT 5000
#define BUF_SIZE    512
int readCommand(int clientSockFd);
void myWrite (int fileDescriptor, const void *buf, size_t nbytes);
int main (void) {
socklen_t client_len;
int optval;
int flags;
struct sockaddr_in serv_addr, client_addr;
int serverSockFd;
int clientSockFd;
fd_set set;
struct timeval timeout;
int rv;
serverSockFd = socket(AF_INET, SOCK_STREAM, 0);
if(serverSockFd < 0) perror("ERROR opening socket");
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(TCP_PORT);
if(bind(serverSockFd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
perror("Unable to bind TCP socket");
}
listen(serverSockFd, 5);
client_len = sizeof(client_addr);
flags = fcntl(serverSockFd, F_GETFL, 0);
if (flags < 0) perror("Unable to read TCP socket flags");
flags = flags|O_NONBLOCK;
fcntl(serverSockFd, F_SETFL, flags);
// Wait for client connections
while(1) {
clientSockFd = accept(serverSockFd, (struct sockaddr *) &client_addr, &client_len);
if(clientSockFd < 0) {
usleep(50000);
continue;
}
//After connected, inner loop to read and write multiple packages
while(1) {
FD_ZERO(&set);
FD_SET(clientSockFd, &set);
timeout.tv_sec = 15;
timeout.tv_usec = 0;
rv = select(clientSockFd+1, &set, NULL, NULL, &timeout);
if(rv == -1) {
perror("select");
continue;
}
else if(rv == 0) {
printf("TCP timeout, closing client connection.n");
shutdown(clientSockFd, 2);
break;
}
if (!readCommand(clientSockFd)) break;
}
close(clientSockFd);
}
close(serverSockFd);
return 0;
}
int readCommand(int sock) {
int nBytes;
int len;
char inBuf[BUF_SIZE];
char outBuf[BUF_SIZE];
nBytes = read(sock, inBuf, BUF_SIZE);
if(nBytes < 0) perror("ERROR reading from TCP socket");
else if(nBytes == 0) {
printf("Client closed TCP socketn");
shutdown(sock, 2);
return nBytes;
}
else {
// Acknowledge command
len = sprintf(outBuf, "Command received: %s", inBuf);
if (write(sock, outBuf, len+1) < 0) {
perror("ERROR writing to TCP socket");
}
// Send response data
if (!strncmp("show version", inBuf, 12)) strcpy(outBuf, "Beta");
else strcpy(outBuf, "Invalid command");
if (write(sock, outBuf, strnlen(outBuf, BUF_SIZE-1)+1) < 0) {
perror("ERROR writing to TCP socket");
}
}
return nBytes;
}

当在localhost上运行客户端时,我刚刚意识到确认和数据都是在第一个read()中消耗的。

因此,在尝试第二次读取之前,我需要解析第一次读取的结果。

最新更新