Linux服务器套接字 - 错误文件描述符

时间:2012-07-31 07:17:01

标签: c linux sockets

我在Linux下遇到服务器套接字问题。由于某些原因我不知道服务器套接字消失了,我在select调用中遇到Bad file descriptor错误,等待进入连接。当我在另一个线程中关闭不相关的套接字连接时,总会发生此问题。这种情况发生在2.6.36内核的嵌入式Linux上。

有谁知道为什么会这样?服务器套接字是否可以简单地消失导致Bad file descriptor

是正常的

修改 另一个套接字代码实现了VNC服务器并在完全不同的线程中运行。其他代码中唯一特别的是使用setjmp/longjmp,但这应该不是问题。

创建服务器套接字的代码如下:

int server_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(1234);

const int optionval = 1;
setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &optionval, sizeof(optionval));

if (bind(server_socket, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
    perror("bind");
    return 0;
}

if (listen(server_socket, 1) < 0) {
    perror("listen");
    return 0;
}

我等待使用以下代码进行连接:

static int WaitForConnection(int server_socket, struct timeval *timeout)
{
    fd_set read_fds;

    FD_ZERO(&read_fds);
    int max_sd = server_socket;
    FD_SET(server_socket, &read_fds);

    // This select will result in 'EBADFD' in the error case.
    // Even though the server socket was not closed with 'close'.
    int res = select(max_sd + 1, &read_fds, NULL, NULL, timeout);
    if (res > 0) {
        struct sockaddr_in caddr;
        socklen_t clen = sizeof(caddr);
        return accept(server_socket, (struct sockaddr *) &caddr, &clen);
    }

    return -1;
}

修改 当问题出现时我目前只是重新启动服务器,但我不明白为什么服务器套接字ID应该突然变成无效的文件描述符:

int error = 0;
socklen_t len = sizeof (error);
int retval = getsockopt (server_socket, SOL_SOCKET, SO_ERROR, &error, &len );
if (retval < 0) {
    close(server_socket);
    goto server_start;
}

4 个答案:

答案 0 :(得分:4)

套接字(文件描述符)通常会遇到与C中的原始指针相同的管理问题。无论何时关闭套接字,都不要忘记将-1分配给保留描述符值的变量:

close(socket);
socket = -1;

正如您对C指针

所做的那样
free(buffer);
buffer = NULL;

如果你忘记这样做,你可以稍后关闭套接字两次,因为如果是指针,你会free()内存两次。

另一个问题可能与人们通常忘记的事实有关:UNIX环境中的文件描述符从0 开始。如果代码中有某处

struct FooData {
    int foo;
    int socket;
    ...
}

// Either
FooData my_data_1 = {0};
// Or
FooData my_data_2;
memset(&my_data_2, 0, sizeof(my_data_2));

在这两种情况下,my_data_1my_data_2都有一个有效的描述符(socket)值。后来,负责释放FooData结构的一些代码可能会盲目地close()这个描述符,恰好是你服务器的监听套接字(0)。

答案 1 :(得分:1)

您无法区分代码中的两个错误情况,两者都可能会失败selectaccept。我的猜测是你只有一个时间,而选择返回0

  • retval分支
  • 中打印errnoelse
  • 单独调查accept的返回值
  • 确保在每次系统调用之前errno重置为0

答案 2 :(得分:0)

1-关闭你的插座:

 public static void fillmyList(ListView myListView, string query)
    {
        myListView.Items.Clear();
        myListView.Columns.Clear();
        string server = "localhost";
        string database = "mydatabaseName";
        string uid = "myUser";
        string password = "MyPassword";
        string connectionString;
        connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
        connection = new MySqlConnection(connectionString);
        try
        {
            //Open connection
            if (OpenConnection() == true)
            {
                //Create Command
                MySqlCommand cmd = new MySqlCommand(query, connection);
                //Create a data reader and Execute the command
                MySqlDataReader dataReader = cmd.ExecuteReader();
                //Read the data and store them in the listview
                if (dataReader.FieldCount > 0)
                {
                    for (int i = 0; i < dataReader.FieldCount; i++)
                    {
                        if (i == 0)
                        {
                            myListView.Columns.Add(dataReader.GetName(0), 0, HorizontalAlignment.Left);
                        }
                        else
                        {
                            myListView.Columns.Add(dataReader.GetName(i).ToString().Replace("_", " "), 80, HorizontalAlignment.Left);
                        }
                    }

                    ListViewItem lv = new ListViewItem();
                    //
                    while (dataReader.Read())
                    {
                        lv = myListView.Items.Add(dataReader[dataReader.GetName(0)].ToString().Replace('_', ' '));
                        for (int h = 1; h < dataReader.FieldCount; h++)
                        {

                                lv.SubItems.Add(dataReader[dataReader.GetName(h)].ToString());
                        }
                    }
                }
                for (int i = 1; i < myListView.Columns.Count; i++)
                    myListView.Columns[i].Width = -2;
                //close Data Reader
                dataReader.Close();
                //close Connection
                CloseConnection();
                         }
        }
        catch (Exception)
        {
            //  MessageBox.Show(ex.Message);
        }


    }

      //open connection to database
    private static bool OpenConnection()
    {
        try
        {
            connection.Open();
            return true;
        }
        catch (MySqlException ex)
        {
            //When handling errors, you can your application's response based on the error number.
            //The two most common error numbers when connecting are as follows:
            //0: Cannot connect to server.
            //1045: Invalid user name and/or password.
            switch (ex.Number)
            {
                case 0:
                    MessageBox.Show("Cannot connect to server.  Contact administrator");
                    break;

                case 1045:
                    MessageBox.Show("Invalid username/password, please try again");
                    break;
            }
            return false;
        }
    }

    //Close connection
    private static bool CloseConnection()
    {
        try
        {
            connection.Close();
            return true;
        }
        catch (MySqlException ex)
        {
            MessageBox.Show(ex.Message);
            return false;
        }
    }

2-从select set中清除套接字文件描述符:

close(sockfd);

答案 3 :(得分:-3)

在Linux中创建连接并关闭后,您必须等待一段时间才能建立新连接。 与在Linux中一样,socket不会释放端口号。一关闭套接字。

你重用套接字,然后想要来坏文件描述符。