就我目前正在写一个服务器应用程序Linux x86_64
使用<sys/socket.h>
。 接受经由连接后accept()
我使用fdopen()
检索到的插座包装到一个FILE*
流。
写入和读取,这FILE*
流通常工作得很好,但插座,只要我写它,而它有一个非空读取缓冲区变unsusable。
出于演示的目的,我已经写了一些代码,监听连接,然后使用读取输入,一行行,流入读取缓冲区, fgetc()
如果线路太长入缓冲区,它不是完全读取,但下一次迭代过程中,而不是阅读。
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
FILE* listen_on_port(unsigned short port) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in name;
name.sin_family = AF_INET;
name.sin_port = htons(port);
name.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sock, (struct sockaddr*) &name, sizeof(name)) < 0)
perror("bind failed");
listen(sock, 5);
int newsock = accept(sock, 0, 0);
return fdopen(newsock, "r+");
}
int main(int argc, char** argv) {
int bufsize = 8;
char buf[9];
buf[8] = 0; //ensure null termination
int data;
int size;
//listen on the port specified in argv[1]
FILE* sock = listen_on_port(atoi(argv[1]));
puts("New connection incoming");
while(1) {
//read a single line
for(size = 0; size < bufsize; size++) {
data = fgetc(sock);
if(data == EOF)
break;
if(data == '\n') {
buf[size] = 0;
break;
}
buf[size] = (char) data;
}
//check if the read failed due to an EOF
if(data == EOF) {
perror("EOF: Connection reset by peer");
break;
} else {
printf("Input line: '%s'\n", buf);
}
//try to write ack
if(fputs("ack\n", sock) == EOF)
perror("sending 'ack' failed");
//try to flush
if(fflush(sock) == EOF)
perror("fflush failed");
}
puts("Connection closed");
}
该代码应在GCC编译没有任何特殊的参数。 与端口号作为参数,并使用netcat的运行它在本地连接到它。
现在,如果你尝试发送是短于8个字符的字符串,这将完美运行。 但是,如果你发送一个包含超过10个字符的字符串,程序将失败。 此示例输入:
ab
cd
abcdefghij
将创建这样的输出:
New connection incoming
Input line: 'ab'
Input line: 'cd'
Input line: 'abcdefgh'
fflush failed: Illegal seek
EOF: Connection reset by peer: Illegal seek
Connection closed
正如你看到的,(正确地)仅ABCDEFGH的前8个字符被读取,但是当程序试图发送“ACK”字符串(客户端从不receves),然后刷新输出缓冲区,我们收到一个Illegal seek
错误,并在下次调用fgetc()
返回EOF。
如果fflush()
部分被注释掉了,同样的错误仍然存在,但
fflush failed: Illegal seek
线从服务器输出失踪。
如果fputs(ack)
部分被注释掉了,似乎一切都按计划工作,但PERROR()从GDB人工呼叫仍然会报告“非法寻求”的错误。
如果双方fputs(ack)
和fflush()
被注释掉了,一切都没有工作的打算。
不幸的是,我没能找到任何好的文件,也没有在这个问题上的任何互联网的讨论,所以你的帮助将不胜感激。
编辑
该解决方案,我终于尘埃落定的是不使用fdopen()
和FILE*
,因为似乎是一个套接字fd转换成的免洗方式FILE*
可以在可靠地使用r+
模式。 相反,我直接制作的套接字fd,写我自己的替换代码fputs
和fprintf
。
如果有人需要它, 这里是代码 。