我正在尝试使用BSD套接字创建一个简单的代理服务器,该套接字在端口上侦听请求,然后将该请求传递到另一台服务器,然后将服务器的响应发送回浏览器。
我可以使用以下代码从浏览器接收REST请求:
void *buffer = malloc(512);
long length = 0;
while (1) {
void *tempBuffer = malloc(512);
long response = recv(acceptedDescriptor, tempBuffer, 512, 0);
if (response == 0 || response < 512) {
free(tempBuffer);
printf("Read %lu bytes\n", length);
break;
}
memcpy(buffer + length, tempBuffer, response);
free(tempBuffer);
length += response;
realloc(buffer, length + 512);
}
但是,当对等方关闭连接时,recv()
应该返回0(在这种情况下是浏览器),但事实并非如此。我能够检测连接是否已关闭的唯一方法是检查响应是否小于recv()
请求的最大量,512字节。这有时会出现问题,因为我看到的一些请求是不完整的。
如果没有更多数据要接收,recv()
阻止并且永不返回,并且将接受的描述符设置为非阻塞意味着读取循环将永远继续,永远不会退出。
如果我:
将侦听套接字描述符设置为非阻塞,当我尝试EAGAIN
连接时,我收到accept()
错误(资源暂时不可用)
将接受的套接字描述符设置为非阻塞,recv()
永远不会返回0并且循环会一直持续
将它们设置为非阻塞,尝试accept()
连接时出现“错误的文件描述符”错误
不要将它们中的任何一个设置为非阻塞,循环永远不会退出,因为recv()
永远不会返回。
套接字本身是按如下方式创建的,但由于它能够检测到请求,因此我看不出它的初始化有什么问题:
int globalDescriptor = -1;
struct sockaddr_in localServerAddress;
...
int initSocket() {
globalDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (globalDescriptor < 0) {
perror("Socket Creation Error");
return 0;
}
localServerAddress.sin_family = AF_INET;
localServerAddress.sin_addr.s_addr = INADDR_ANY;
localServerAddress.sin_port = htons(8374);
memset(localServerAddress.sin_zero, 0, 8);
int res = 0;
setsockopt(globalDescriptor, SOL_SOCKET, SO_REUSEADDR, &res, sizeof(res));
//fcntl(globalDescriptor, F_SETFL, O_NONBLOCK);
return 1;
}
...
void startListening() {
int bindResult = bind(globalDescriptor, (struct sockaddr *)&localServerAddress, sizeof(localServerAddress));
if (bindResult < 0) {
close(globalDescriptor);
globalDescriptor = 0;
perror("Socket Bind Error");
exit(1);
}
listen(globalDescriptor, 1);
struct sockaddr_in clientAddress;
int clientAddressLength = sizeof(clientAddress);
while (1) {
memset(&clientAddress, 0, sizeof(clientAddress));
clientAddressLength = sizeof(clientAddress);
int acceptedDescriptor = accept(globalDescriptor, (struct sockaddr *)&clientAddress, (socklen_t *)&clientAddressLength);
//fcntl(acceptedDescriptor, F_SETFL, O_NONBLOCK);
if (acceptedDescriptor < 0) {
perror("Incoming Connection Error");
exit(1);
}
void *buffer = malloc(512);
long length = 0;
while (1) {
void *tempBuffer = malloc(512);
long response = recv(acceptedDescriptor, tempBuffer, 512, 0);
if (response == 0) {
free(tempBuffer);
printf("Read %lu bytes\n", length);
break;
}
memcpy(buffer + length, tempBuffer, response);
free(tempBuffer);
length += response;
realloc(buffer, length + 512);
}
executeRequest(buffer, length, acceptedDescriptor);
close(acceptedDescriptor);
free(buffer);
}
}
...
仅当startListening()
返回1:
initSocket()
函数
int main(int argc, const char *argv[]) {
if (initSocket() == 1) {
startListening();
}
return 0;
}
我可能在这里做了一些愚蠢的事情,但我很感激您对这个问题的任何信息以及如何解决这个问题。