我已经在服务器端为使用C的聊天客户端编写了以下代码。但是,在while循环中我需要检查客户端是否已退出程序,即是否与客户端的连接丢失。请告诉我如何编写这样的代码。
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
int main()
{
int sock, connected, bytes_recieved , true = 1, pid;
char send_data [1024] , recv_data[1024];
struct sockaddr_in server_addr,client_addr;
int sin_size;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Socket");
exit(1);
}
if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1)
{
perror("Setsockopt");
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(3128);
server_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(server_addr.sin_zero),8);
if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror("Unable to bind");
exit(1);
}
if (listen(sock, 5) == -1)
{
perror("Listen");
exit(1);
}
printf("\nTCPServer Waiting for client on port 3128");
fflush(stdout);
FILE *log;
log = fopen("time.log", "a");
time_t t;
while(1)
{
sin_size = sizeof(struct sockaddr_in);
connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);
printf("\n I got a connection from (%s , %d)", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
fflush(stdout);
int pid=fork();
while(1)
{
if(pid == 0)
{
usleep(1000000);
time(&t);
send(connected, ctime(&t),30, 0);
}
else
{
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
fputs(recv_data, log);
fputs("Time: ", log);
time(&t);
fputs(ctime(&t), log);
}
fflush(log);
}
}
fclose(log);
close(sock);
return 0;
}
请帮忙。
现在我修改了这样的代码:
while(1)
{
if(pid == 0)
{
usleep(1000000);
time(&t);
send(connected, ctime(&t),30, 0);
}
else
{
bytes_recieved = recv(connected,recv_data,1024,0);
recv_data[bytes_recieved] = '\0';
fputs(recv_data, log);
fputs("Time: ", log);
time(&t);
fputs(ctime(&t), log);
}
fflush(stdout);
fflush(log);
fclose(log);
if(bytes_recieved == 0 || bytes_recieved == -1)
{
close(sock); goto connct;}
}
}
close(sock);
return 0;
在编译时,它很好,但在运行时,它会输出以下错误:
*** glibc detected *** ./server: double free or corruption (!prev): 0x09936008 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6b381)[0xb7659381]
/lib/i686/cmov/libc.so.6(+0x6cbd8)[0xb765abd8]
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb765dcbd]
/lib/i686/cmov/libc.so.6(fclose+0x14a)[0xb764982a]
./server[0x8048c21]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb7604ca6]
./server[0x8048861]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 133298 /home/harikrishnan/server/server
08049000-0804a000 rw-p 00000000 08:01 133298 /home/harikrishnan/server/server
09936000-09957000 rw-p 00000000 00:00 0 [heap]
b7400000-b7421000 rw-p 00000000 00:00 0
b7421000-b7500000 ---p 00000000 00:00 0
b75bf000-b75dc000 r-xp 00000000 08:01 3653635 /lib/libgcc_s.so.1
b75dc000-b75dd000 rw-p 0001c000 08:01 3653635 /lib/libgcc_s.so.1
b75ed000-b75ee000 rw-p 00000000 00:00 0
b75ee000-b772e000 r-xp 00000000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b772e000-b772f000 ---p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b772f000-b7731000 r--p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b7731000-b7732000 rw-p 00142000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b7732000-b7735000 rw-p 00000000 00:00 0
b7744000-b7747000 rw-p 00000000 00:00 0
b7747000-b7748000 r-xp 00000000 00:00 0 [vdso]
b7748000-b7763000 r-xp 00000000 08:01 3654097 /lib/ld-2.11.3.so
b7763000-b7764000 r--p 0001b000 08:01 3654097 /lib/ld-2.11.3.so
b7764000-b7765000 rw-p 0001c000 08:01 3654097 /lib/ld-2.11.3.so
bfd94000-bfda9000 rw-p 00000000 00:00 0 [stack]
*** glibc detected *** ./server: double free or corruption (!prev): 0x09936008 ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6b381)[0xb7659381]
/lib/i686/cmov/libc.so.6(+0x6cbd8)[0xb765abd8]
/lib/i686/cmov/libc.so.6(cfree+0x6d)[0xb765dcbd]
/lib/i686/cmov/libc.so.6(fclose+0x14a)[0xb764982a]
./server[0x8048c21]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb7604ca6]
./server[0x8048861]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:01 133298 /home/harikrishnan/server/server
08049000-0804a000 rw-p 00000000 08:01 133298 /home/harikrishnan/server/server
09936000-09957000 rw-p 00000000 00:00 0 [heap]
b7400000-b7421000 rw-p 00000000 00:00 0
b7421000-b7500000 ---p 00000000 00:00 0
b75bf000-b75dc000 r-xp 00000000 08:01 3653635 /lib/libgcc_s.so.1
b75dc000-b75dd000 rw-p 0001c000 08:01 3653635 /lib/libgcc_s.so.1
b75ed000-b75ee000 rw-p 00000000 00:00 0
b75ee000-b772e000 r-xp 00000000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b772e000-b772f000 ---p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b772f000-b7731000 r--p 00140000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b7731000-b7732000 rw-p 00142000 08:01 3670051 /lib/i686/cmov/libc-2.11.3.so
b7732000-b7735000 rw-p 00000000 00:00 0
b7744000-b7747000 rw-p 00000000 00:00 0
b7747000-b7748000 r-xp 00000000 00:00 0 [vdso]
b7748000-b7763000 r-xp 00000000 08:01 3654097 /lib/ld-2.11.3.so
b7763000-b7764000 r--p 0001b000 08:01 3654097 /lib/ld-2.11.3.so
b7764000-b7765000 rw-p 0001c000 08:01 3654097 /lib/ld-2.11.3.so
bfd94000-bfda9000 rw-p 00000000 00:00 0 [stack]
Aborted
知道实际问题是什么吗?
答案 0 :(得分:3)
recv()
将返回0
。如果在尝试从套接字获取数据时出现任何错误,将返回-1
。
有关详细信息,请参阅man page。
所以将代码更改为
int conn_closed = 0;
bytes_recieved = recv(connected,recv_data,1024,0);
switch (bytes_recieved) {
case 0:
/* connection closed by client */
close(connected);
conn_closed = 1;
break;
case -1:
/* error on socket */
/* TODO: insert error handling code */
if (errno == EAGAIN || errno == EINTR) {
/* safe to retry */
conn_closed = 0;
} else {
close(connected)
conn_closed = 1;
}
break;
default:
recv_data[bytes_recieved] = '\0';
fputs(recv_data, log);
fputs("Time: ", log);
time(&t);
fputs(ctime(&t), log);
conn_closed = 0;
break;
}
/* break out of the loop if conn_closed */
if (conn_closed)
break;
并且不要忘记检查send()
的返回值,以查看发送数据时是否发生错误。
更新:为EAGAIN
和EINTR
添加了错误处理代码。
第二次更新:
为了完整性,以下是您应该添加的用于发送的代码
if (send(connected, ctime(&t),30, 0) == -1)
{
if (errno == EAGAIN || errno == EINTR) {
/* retry to send */
}
close(connected);
break;
}
答案 1 :(得分:0)
如果发送返回SOCKET_ERROR,表示套接字已关闭或连接丢失
所以只做
if (send(connected, ctime(&t),30, 0) == SOCKET_ERROR)
{
// blablabla
}
答案 2 :(得分:0)
在您的情况下,一个小建议,而不是给出检查连接的'if'条件,在'while'内部执行相同的操作,而不是'while(1)',给出条件。