我正在尝试使用 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);
}
}
...
仅当返回 1时才调用该startListening()
函数:initSocket()
int main(int argc, const char *argv[]) {
if (initSocket() == 1) {
startListening();
}
return 0;
}
我可能在这里做了一些愚蠢的事情,但我很感激您提供有关此问题以及如何解决此问题的任何信息。