我正在尝试在 C 中实现一个 TCP 客户端,它需要按如下方式工作:
- 能够打开到给定服务器的连接
- 能够通过已建立的连接向服务器发送任意数据,以及
- 能够从服务器接收任意数据(将其视为对我的客户端发送到服务器的“问题”的响应)。
例如,客户端应该能够打开与任意 HTTP 服务器的连接,发送“HEAD”消息并打印来自 HTTP 服务器的响应。
(我的目标是为我日常工作使用的特定软件环境创建一个通用的“TCP 客户端插件”,该软件环境缺乏网络功能。我非常了解我的环境的 SDK,但我真的没有套接字编程方面的深厚经验。)
目前,我有 2 个单独的线程用于发送和接收数据。接收线程的工作流程(只要用户设置了服务器地址和端口就会自动启动)如下(这里我只提到套接字调用的主序列):
globalSocket = socket(); // Create socket and store it globally
bind(); // Bind the local port
connect(); // Connect to remote host & port
listen(); // Listen to the socket
while (isAlive) {
select(... &readfds ...); // Check for ready reader descriptors
accept(); // Accept the incoming connection
recv(); // Receive data from server
}
close(); // End the connection
发送者线程很简单,它使用globalSocket
接收者线程创建的来执行send()
命令。
现在,这是我的问题:我可以毫无问题地打开与远程服务器的连接。我也可以毫无问题地发送任意数据(我确认我发送的数据实际到达服务器端没有问题)。但是,我无法从服务器取回任何数据。经过一些测试,似乎select
永远不会返回正值。
我在我的代码中尝试了很多修改(比如将参数更改为select
、省略listen
等),我在这一天至少阅读了 Beej 的指南 10 次,并尝试了我能想象的每一个临时更改,但行为仍然相同。因此,在我开始使用特定代码摘录提出特定问题之前,我想知道我解决这个问题的方法是否正确,或者我是否在这里遇到了一些严重的概念问题。
确实感谢您的回答,
亚当
PS 我无法在评论中发布此代码部分,因为它太长了;这是管理select
- accept
-recv
循环的代码片段:
while ( thread->isActive ) {
// Accept connection
timeVal.tv_sec = TIMEOUT_SEC;
timeVal.tv_usec = TIMEOUT_USEC;
FD_ZERO( & fileDescriptor );
FD_SET( socketDescriptor, & fileDescriptor ); // socketDescriptor is the global socket
result = select ( FD_SETSIZE, & fileDescriptor, NULL, NULL, & timeVal );
if ( result > 0 ) {
post ( "select" ); // This line is actually never reached
connectionDescriptor = accept ( socketDescriptor, ( struct sockaddr * ) & clientAddress, & clientLength ); // connectionDescriptor is the local socket created by accept
if ( connectionDescriptor < 0 ) { // Some error happened
outlet_int ( thread->parent->statusOutlet, errno );
} else {
// Receive data
data.clear ( ); // 'data' is an std::vector of chars that stores the incoming data and makes it accessible for the rest of the environment
size = thread->parent->bufferSize;
buffer = new unsigned char [ size ]; // this buffer is used for receiving the data from 'recv'
receivedBytes = 1;
while ( receivedBytes > 0 ) {
receivedBytes = recv ( connectionDescriptor, ( char * ) buffer, size, 0 );
if ( receivedBytes < 0 ) { // Socket error
outlet_int ( thread->parent->statusOutlet, errno );
}
data.insert ( data.end ( ), buffer, buffer + receivedBytes );
}
delete [ ] buffer;
#ifdef WIN_VERSION
closesocket ( connectionDescriptor );
#else
close ( connectionDescriptor );
#endif
// Output received data
... blah ... blah ... blah
}
}
}