我正在实现一个简单的TCP进程每客户端并发回显服务器。服务器无法从第一个客户端读取字符串。但是对于其他客户端,服务器会正确回送字符串。我觉得阅读字符串可能有些问题;服务器端无法检测到EOF。我尝试使用send()/ recv()而不是read()/ write()但没有成功。我还尝试了从stdin读取字符串的其他函数 - 即fgets(),scanf()等。
这个问题的可能原因是什么;即服务器无法仅从第一个客户端读取?
服务器和客户端的代码位于 -
之下// server.c
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define BUF_SIZE 4096
#define MAXPENDING 256
static void zombieReaper(int sig)
{
while (waitpid(-1, NULL, WNOHANG) > 0)
continue;
}
static void handleRequest(int cfd)
{
char buf[BUF_SIZE];
int numread;
int size = BUF_SIZE;
int i;
printf("\n inside handling request fd : %d ", cfd);
fflush(stdout);
while (1) {
numread = read(cfd, buf, size);
if (numread > 0) {
int l = strlen(buf);
printf("Echo server numread : %d len : %d buf : %s\n", numread, l, buf);
fflush(stdout);
buf[l] = '\0';
write(cfd, buf, size);
}
}
}
int main(int argc, char *argv[])
{
int lfd, cfd;
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = zombieReaper;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
printf("SIGCHILD signal");
exit(0);
}
struct sockaddr_in serv_addr, clnt_addr;
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd == -1) {
printf("Socket Failed");
exit(0);
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[1]));
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(lfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("bind() failed");
exit(0);
}
if (listen(lfd, MAXPENDING) < 0) {
printf("listen() failed");
exit(0);
}
socklen_t clen = sizeof(clnt_addr);
int status = 0;
for (;;) {
if (cfd = accept(lfd, (struct sockaddr *) &clnt_addr, &clen) < 0) {
printf("accept() failed");
} else {
printf("Accepted client cfd : %d\n", cfd);
switch (fork()) {
case -1:
close(cfd);
break;
case 0: // Child
close(lfd);
handleRequest(cfd);
exit(1);
default: // Parent
close(cfd);
break;
}
}
}
}
// client.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUF_SIZE 4096
int main(int argc, char *argv[])
{
int clnt_fd;
struct sockaddr_in serv_addr;
//memset(&serv_addr, 0, sizeof(serv_addr));
char cmd[BUF_SIZE];
char buf[BUF_SIZE];
clnt_fd = socket(PF_INET, SOCK_STREAM, 0);
if (clnt_fd == -1) {
printf("socket() failed");
exit(0);
}
// prepare for connect
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(atoi(argv[2]));
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
// connect to server
if (connect(clnt_fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
printf("connect() failed");
exit(0);
}
int size = BUF_SIZE;
while (1) {
printf("\n Enter a string (q to Exit) : \n ");
gets(cmd);
if (!strcmp(cmd, "q"))
break;
int n = write(clnt_fd, cmd, strlen(cmd));
n = read(clnt_fd, buf, BUF_SIZE);
printf("\n Received Results : \n %s\n", buf);
}
close(clnt_fd);
return 0;
}
答案 0 :(得分:1)
代码中的问题是,
if (cfd = accept(lfd, (struct sockaddr *) &clnt_addr, &clen) < 0)
这里当你接受时,你正在使用关系运算符 验证后,返回值0存储在cfd。 假设原始的accept套接字id为4,但返回值为0 根据您在程序中执行某些操作的返回值。 尝试使用条件的优先级,例如 现在它打印完全接受的套接字ID。if ((cfd = accept(lfd, (struct sockaddr *) &clnt_addr, &clen)) < 0)
答案 1 :(得分:0)
if (numread > 0) {
int l = strlen(buf);
这里假设缓冲区中有空值。相反,您应该只使用下面的numread
。
printf("Echo server numread : %d len : %d buf : %s\n", numread, l, buf);
这里再次假设缓冲区中存在空值。它应该是
printf("Echo server numread : %d buf : %.*s\n", numread, numread, buf);
现在: buf [l] =&#39; \ 0&#39 ;;
如果您找到它,那么您将在您已经找到它的地方放置一个null。删除。
write(cfd, buf, size);
在这里,您将错误的数据量写回发件人。它应该是write(cfd, buf, numread).
}
在这里,如果numread <= 0
,你将无法摆脱循环。
printf("socket() failed");
printf("connect() failed");
printf("bind() failed");
printf("listen() failed");
printf("accept() failed");
在这些地方中,您打印的是您自己设计的相当无用的错误消息,并忽略实际错误。不要这样做。在每个地方将printf
更改为perror
,或将strerror()
的结果添加到邮件中。