2016-12-28 133 views
-1

我想用C其中工程样的这种方式使用TCP套接字来实现协议:TCP套接字冻结服务器

  1. 客户端连接到服务器并发送文件名,它要 下载
  2. 服务器读取值,并检查它是否是有效的文件名(它存在于服务器上)+发送ACCEPTFAILURE状态,客户端
  3. 客户端读取状态,并准备自己下载+发送READY状态服务器
  4. 服务器发送文件并关闭连接

Server代码

char response[128]; 
int bytes_read; 
while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

if (valid_request(files, files_count, response)) { 
    write(info.socket, MC_ACCEPT, 4); 
} else { 
    write(info.socket, MC_FAILURE, 4); 
} 

客户端代码

int w_status = write(sck, requested_file, strlen(requested_file)); 
if (w_status < 0) { 
    fprintf(stderr, "Error writing to socket. Status: %d", w_status); 
    exit(1); 
} 

char status[4]; 
while ((resp = read(sck, status, 4)) > 0) {} 

if (strcmp(status, MC_ACCEPT) == 0) { 
    printf("ACCEPTED!\n"); 
} else if (strcmp(status, MC_ACCEPT) == 0) { 
    printf("FAILURE\n"); 
} else { 
    printf("DONT KNOW\n"); 
} 

close(sck); 

的问题是,服务器冻结本身的read()一部分。它看起来像客户端发送文件名并等待服务器响应(状态),但服务器被冻结在read()

我以某种方式阻止TCP套接字?我的推理出了什么问题?

+0

@Barmar我的错,我没有在我的实际代码 –

+0

您是否尝试过做一个数据包捕获,看看消息是否是发送到服务器? – Barmar

+0

@Barmar当我第一次运行一个服务器,然后客户端和它挂起时,什么是有趣的,但之后,我用CTRL + C终止客户端进程,服务器似乎得到的消息恰到好处,但直到客户端进程还活着 –

回答

1

在服务器端:

char response[128]; 
int bytes_read; 
while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

您尝试在几个read调用读那些128个字符。但是它会永远阻塞直到客户端关闭套接字(它是TCP连接的,除非对等关闭连接,总会有东西要读取)。

如果数据到达超过1个块,则代码不正确,因为第一个块将被下一个块覆盖,依此类推。您必须更改缓冲区的偏移量,并且不要每次都尝试读取128个字节,否则会卡住。

int bytes_read = 0; 
while (bytes_read < 128) 
{ 
    int currently_read = read(info.socket, response + currently_read, 128-bytes_read); 
    bytes_read += currently_read; 
} 

在客户端,相同类型的问题太多:

你似乎等待4个字符。

您尝试阅读第一个read中的那4个字符。但是你不检查是否有4个字符被实际读取(返回代码丢弃)。

之后,您使用循环读取,直到您获得0个字节。但是因为连接并没有结束,所以你被困在那里。

你想要的是在做别的事情之前正好读取4个字节。

并增加缓冲区大小& null-terminate你的字符串或strcmp将会失败。

char status[5]; 
status[4] = '\0'; 
int nb_read = 0; 
while (nb_read < 4) 
{ 
    int currently_read = read(sck, status + nb_read, 4-nb_read); 
    nb_read += currently_read; 
} 
+0

你的解释是理解我的问题的关键。谢谢。 –

0

的问题是,你不处理while循环内的请求:

while ((bytes_read = read(info.socket, response, 128)) > 0) {} 

这样可以使循环,直到read()回报0,这发生在客户端关闭连接,或者收到错误并返回-1。在从客户端读取请求后,它将返回并再次呼叫read()。由于客户端没有发送任何其他内容,因此会阻止。

这就是为什么杀死客户端将其取消的原因。关闭连接,所以它获得EOF并且read()返回0

您需要处理循环内的输入:

while ((bytes_read = read(info.socket, response, sizeof response -1)) > 0) { 
    response[bytes_read] = '\0'; // add string null terminator 
    if (valid_request(files, files_count, response)) { 
     write(info.socket, MC_ACCEPT, 4); 
    } else { 
     write(info.socket, MC_FAILURE, 4); 
    } 
} 
+0

但无法读取(info.socket,response,sizeof response -1)'返回小于'sizeof response -1'? –

+0

是的,它可以。他实际上需要设计协议,以便服务器可以通过某种方式来确定请求的结束位置,或者使用长度前缀或分隔符,然后继续阅读,直到获取完整消息。如果没有这个,他所能做的最好的就是希望'read()'将返回整个消息,这是相当可能的。 – Barmar