我正在测试用于传输基于文本的文件的套接字代码,并通过参考《 Unix网络编程》(中文版)这本书来编写此代码。简要地说,我将在下面粘贴一些代码:
我的serve_client函数:
void serve_client(int connfd, const char *filename, size_t filesize)
{
char header[1024];
int fd = open(filename, O_RDONLY, 0);
char *file_mapped;
if (fd == -1)
{
char *not_found = "HTTP/1.1 404 NOT FOUND\r\n";
send(connfd, not_found, strlen(not_found), 0);
}
else
{
sprintf(header, "HTTP/1.1 200 OK\r\n");
sprintf(header, "%sContent-Length: %u\r\n", header, filesize);
sprintf(header, "%sContent-Type: text/plain; charset=utf-8\r\n\r\n", header);
// send http response header
send(connfd, header, strlen(header), 0);
printf("Response headers:\n");
printf("%s", header);
file_mapped = (char *)mmap(0, filesize, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
// send http response body
send(connfd, file_mapped, filesize, 0);
int unmapped = munmap(file_mapped, filesize);
if (unmapped == -1)
{
perror("memory unmapped failed!");
_exit(1);
}
}
}
我想问你们几个问题:
此serve_client()
函数成功返回后,我的意思是至少我需要的数据应该完全复制到内核缓冲区中,以便在不久的将来发送。我对吗?
shutdown()
函数的调用如下:
serve_client(connfd, path, st.st_size);
shutdown(connfd, SHUT_WR);
// thread or process ends
我检查了本书中提到的技巧,它说,带有此选项SHUT_WR
的此功能将导致首先发送保留在内核缓冲区中的数据,然后发送最后的FIN。是吗?
wget
或仅通过Web访问。任何建议都很好。现在,通过执行此操作来解决此问题,让客户端关闭连接,让服务器等待FIN到达。有用。但仍然不是我想要的。 :(
while (1)
{
ssize_t bytes_read = recv(connfd, buf, 1024, 0);
if (bytes_read > 0)
{
continue;
}
else if (bytes_read == 0)
{
close(connfd);
break;
}
else
{
// < 0
// handle error
close(connfd);
break;
}
}
编辑很抱歉,这个问题引起了误解,转储显示了从服务器发送的RST,就像我被告知的那样,该过程过早退出。这就是先前的代码无法正常工作的原因。谢谢您的所有解释,确实有助于我更好地了解幕后进度。
答案 0 :(得分:1)
Ending a process隐式close()
所有文件/套接字描述符。这就是问题所在。发送后关闭可能会导致接收方丢失数据(取决于TCP堆栈的实现)。
您需要实现一个应用程序级别的协议,让客户端在服务器关闭套接字之前确认已接收所有数据。
总结:使用closure of a socket as part of the application level protocol is not reliable。不要这样做。