4

我已经在这个网站上搜索了所有关于这个问题的信息。

我的程序方案是:

  • 有一个服务器总是监听来自客户端的请求。
  • 有一个客户端总是char在 2 秒内向服务器请求

得到错误信息:

在程序运行大约 1024 次后,socket() 函数上发生了太多打开的文件。

我目前的解决方案是增加打开文件的数量: "ulimit -n 5000",但我认为这不是一个完美的解决方案,因为它会使程序运行 5000 次。

那么,有人有更好的解决方案吗?

环境:

  • Ubuntu 10
  • c语言

我的代码如下:

客户:

    int sockfd;
    struct sockaddr_in address;
int socket_port = 9734;

while (1) {

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
        DieWithSystemMessage("socket() failed");//<<===========Too many open files
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr("127.0.0.1");
    address.sin_port = socket_port;
    //Establish the connection to the server
    if ((connect(sockfd, (struct sockaddr *) &address, sizeof(address)))
            < 0)
        DieWithSystemMessage("connect() failed");

    if (rename_count % 2 == 0)
        ch = 'A';
    else if (rename_count % 2 == 1)
        ch = 'B';
    else
        ch = 'E';
    ssize_t numBytes = send(sockfd, &ch, strlen(&ch), 0);

    if (numBytes < 0)
        DieWithSystemMessage("send() failed");
    else if (numBytes != strlen(&ch))
        DieWithUserMessage("send()", "sent unexpected number of bytes");
    //fflush(sockfd);
    shutdown(sockfd, SHUT_RDWR);

    rename_count++;

}

服务器:

int server_sockfd, client_sockfd;
int server_len, client_len;
socklen_t clntAddrLen;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
uint64_t start_time_micro, end_time_micro;
int socket_num = 9734;

server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (server_sockfd < 0)
    DieWithSystemMessage("socket() failed");

memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
server_address.sin_port = socket_num;

if ((bind(server_sockfd, (struct sockaddr *) &server_address,
        sizeof(server_address))) < 0)
    DieWithSystemMessage("bind() failed");
if ((listen(server_sockfd, 5)) < 0)
    DieWithSystemMessage("listen() failed");


while (1) {
    char ch;
    printf("\nserver waiting\n");

    //accept a connect
    clntAddrLen = sizeof(client_address);
    client_sockfd = accept(server_sockfd,
            (struct sockaddr *) &client_address, &clntAddrLen);
    if (client_sockfd < 0)
        DieWithSystemMessage("accept() failed");
    //reading and writing through client side
    ssize_t numBytesRcvd = recv(client_sockfd, &ch, 1, 0);
    if (numBytesRcvd < 0)
        DieWithSystemMessage("recv() failed");

    if (ch == 'A') {
        rename_num = 0;//printf("A\n");
    } else if (ch == 'B') {
        rename_num = 1;//printf("B\n");
    } else
        ;

    printf("%d. Got it!!!\n", i);

    close(client_sockfd);
}
close(server_sockfd);
4

2 回答 2

3

shutdown()和之间有很大区别close()。当您“关闭”一个套接字时,您将其置于“半关闭”状态,仍然可以通过连接发送或接收(取决于您关闭哪一半)。

套接字仍然有效,TCP 仍然维护有关连接的状态信息,端口仍然“打开”,并且套接字/文件描述符仍然分配给您的进程。

当您调用close()套接字/文件描述符时,它是免费的,但其余的仍然是. TCP 必须持有资源一段时间,通常是 2 分钟(这取决于谁做了关闭和其他一些事情),在此期间状态信息和本地端口本身仍在“使用中”。

因此,即使您可能不再超过进程的文件描述符限制,理论上也有可能使网络堆栈的资源饱和并且仍然无法打开新连接。

于 2012-11-02T13:31:24.127 回答
3

您正在关闭客户端中的套接字,但从不关闭它。这不是一回事。

于 2012-11-02T11:21:25.117 回答