我有这个服务器应用程序,为客户端连接设置本地通信流套接字。如果启动了服务器的第二个实例并且它尝试绑定到同一地址(文件名),则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()
上失败,但不会失败。
答案 0 :(得分:2)
由于:
unlink(TS_SERVER);
删除现有的套接字文件,允许在其位置创建新的套接字文件。