我正在尝试在C中创建一个TCP客户端程序,客户端将在该程序中启动,连接到服务器。然后它会发送一些信息,然后只听取它收到的内容并作出相应的反应。
我遇到麻烦的部分是持续聆听。这就是我所拥有的
...
while (1) {
numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0);
buf[numbytes] = '\0';
printf("Received: %s\n", buf);
// more code to react goes here
}
...
连接到服务器后,在发送两行数据后,服务器应该收到一些信息,但是当我运行它时,会打印出来:
收到:
然后继续坐在那里,直到我强迫它关闭。
**编辑**当我做乔纳森告诉我要做的事情时,我得到以下内容:
计数:-1,错误:111,收到:
这意味着它的错误,但我该怎么办呢?
答案 0 :(得分:4)
打印出接收的字节数 - 它可能为零,但请确认。
值得检查的是,您没有收到错误 - 因此会使您的缓冲区下溢。
[注意:从此开始是Pax的工作 - 谢谢,我已将其转换为社区Wiki,因此我不会得到不正当的代表点。
以下代码将执行此操作。请尝试并报告结果。
while (1) {
numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0);
buf[numbytes] = '\0';
printf("Count: %d, Error: %d, Received: %s\n", numbytes, errno, buf);
// more code to react goes here
}
问题编辑后:
错误号111是ECONNREFUSED - 这不是recv()的常见错误代码,但更适合开放式调用(open(),connect()等)。
在任何情况下,ECONNREFUSED都是服务器端的问题,而不是客户端 - 服务器故意拒绝接受您的传入连接,因此您需要调查链接的那一端。
为了对此进行测试,请更改您的代码,使其在端口80上连接到www.microsoft.com,然后发送几行任何旧垃圾。您应该从其Web服务器返回错误,指示格式错误的HTTP请求。这将证明您的客户端没有问题。
这是我telnet www.microsoft.com 80
时回来的,然后输入hello
后跟ENTER
两次:
HTTP/1.1 400 Bad Request
Content-Type: text/html; charset=us-ascii
Server: Microsoft-HTTPAPI/2.0
Date: Thu, 27 Nov 2008 01:45:09 GMT
Connection: close
Content-Length: 326
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid Verb</h2>
<hr><p>HTTP Error 400. The request verb is invalid.</p>
</BODY></HTML>
你应该看到类似的东西。
答案 1 :(得分:2)
我强烈推荐Beej's Guide to Network Programming。
This section特别是客户端的代码完全符合您的要求。
答案 2 :(得分:0)
请显示更多代码。
虽然有一些观察:
listen()ing
?accept()ed
传入连接recv()
有点不寻常。请改用read()
。strerror()
将111错误代码转换为本地错误字符串 - 每个UNIX O / S都有自己的映射,从数字到Exxx错误代码,因此我们无法分辨出您的系统出现此错误普通代码循环(对于单线程非分叉应用程序)看起来像:
s = socket();
err = listen(s, n); // n = backlog number
while (1) {
int fd = accept(s, &addr, sizeof(addr));
while (1) {
int numrecv = read(fd, ...);
// break if eof
}
close(fd);
}
close(s);
答案 3 :(得分:0)
无限循环是什么?为什么不使用select(),这样只有在要读取实际数据时才调用recv()?
在以前的生活中,我为MUD编写了网络代码,我仍然可以在脑海中编写轮询循环。 ROM 2.3中的循环是这样的(从内存中,如果宏参数的顺序错误,请原谅我):
#define MAX_CONNECTIONS 256
int main(int argc, char *argv[])
{
int i = 0;
int running = 1;
int connections[MAX_CONNECTIONS];
while( running )
{
fd_set in_fd, out_fd, exc_fd;
FD_ZERO(in_fd);
FD_ZERO(out_fd);
FD_ZERO(exc_fd);
for( i = 0; i < MAX_CONNECTIONS; i++ )
{
if( connections[i] > 0 )
{
FD_SET(&in_fd, connections[i]);
FD_SET(&out_fd, connections[i]);
FD_SET(&exc_fd, connections[i]);
}
}
select(&in_fd, &out_fd, &exc_fd, NULL); // this will block until there's an I/O to handle.
for( i = 0; i < MAX_CONNECTIONS; i++ )
{
if( FD_ISSET(&exc_fd, connections[i]) )
{ /* error occurred on this connection; clean up and set connection[i] to 0 */ }
else
{
if( FD_ISSET(&in_fd, connections[i]) )
{ /* handle input */ }
if( FD_ISSET(&out_fd, connections[i]) )
{ /* handle output */ }
}
}
}
}