Linux本地通信套接字:为什么bind()没有按预期失败?

时间:2015-06-09 20:45:59

标签: c linux sockets bind

我有这个服务器应用程序,为客户端连接设置本地通信流套接字。如果启动了服务器的第二个实例并且它尝试绑定到同一地址(文件名),则bind()将失败并显示EADDRINUSE。但事实并非如此。为什么呢?

以下是展示问题的简化代码:

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>

int make_socket(const char *filename, int style) {
   struct sockaddr_un name;
   int sock;
   size_t size;

   sock = socket(PF_LOCAL, style, 0);
   if (sock < 0) {
      perror("socket");
      exit(EXIT_FAILURE);
   }

   if ((!filename) || (filename[0] == '\0')) {
      return sock;
   }

   name.sun_family = AF_LOCAL;
   strncpy(name.sun_path, filename, sizeof(name.sun_path));
   name.sun_path[sizeof(name.sun_path) - 1] = '\0';
   size = SUN_LEN(&name);

   if (bind(sock, (struct sockaddr *) &name, size) < 0) {
      perror("bind");
      exit(EXIT_FAILURE);
   }

   return sock;
}

int make_stream_socket(const char *filename) {
   return make_socket(filename, SOCK_STREAM);
}

#define TS_SERVER  "/tmp/socket-server"

int main(int argc, char *argv[]) {
   int sock_server, sock_client;
   struct sockaddr_un name_client;
   size_t size_name_client;
   int i;
   fd_set client_set, selected_set;
   int quitting = 0;

   fprintf(stderr, "Server: starting up\n");
   unlink(TS_SERVER);
   sock_server = make_stream_socket(TS_SERVER);
   fprintf(stderr, "Server: accepting connections on %d\n", sock_server);
   if (0 > listen(sock_server, 1)) {
      perror("listen(connection requests)");
      exit(EXIT_FAILURE);
   }
   FD_ZERO(&client_set);
   FD_SET(sock_server, &client_set);
   while (!quitting) {
      fprintf(stderr, "Server: waiting for connections\n");
      selected_set = client_set; //shallow-clone client_set
      if (0 > select(FD_SETSIZE, &selected_set, NULL, NULL, NULL)) {
         perror("select(for readability)");
         exit(EXIT_FAILURE);
      }

      fprintf(stderr, "Server: connection(s) received\n");
      for (i = 0; i < FD_SETSIZE; ++i) {
         if (FD_ISSET(i, &selected_set)) {
            if (i == sock_server) {
               fprintf(stderr, "Server: accepting connection\n");
               size_name_client = sizeof(name_client);
               sock_client = accept(sock_server,
                                    (struct sockaddr *) &name_client, 
                                    (socklen_t *) &size_name_client);
               //Ubuntu Launchpad bug 1463553: accept() returns
               // an off-by-one size_name_client
               size_name_client = SUN_LEN(&name_client);
               if (sock_client < 0) {
                  perror("accept(connection request)");
                  exit(EXIT_FAILURE);
               }
               fprintf(stderr, "Server: accepted connection request from '%s' on %d\n",
                               name_client.sun_path, sock_client);
               quitting = 1;
               close(sock_client);
               break; //out of the for
            } //if (i == sock_server)
         } //if (FD_ISSET(i, &selected_set))
      } //for
   } //while

   fprintf(stderr, "Server: shutting down\n");
   close(sock_server);
   unlink(TS_SERVER);

   exit(EXIT_SUCCESS);
}

编译后,从命令行运行第一个实例,然后从另一个命令行运行第二个实例。第二个实例应该在bind()上失败,但不会失败。

1 个答案:

答案 0 :(得分:2)

由于:

  unlink(TS_SERVER);

删除现有的套接字文件,允许在其位置创建新的套接字文件。