【发布时间】:2017-04-03 19:12:25
【问题描述】:
我正在尝试编写一个简单的套接字服务器,就本示例而言,它是一个回显服务器。
这是 socket_server.c(注意关于卡在哪里的注释)
int fdmax, i, socket_descriptor;
fd_set master, read_fds;
struct timeval tv = {.tv_sec = 0, .tv_usec = 1000};
void socket_server_init(void)
{
FD_ZERO(&master);
FD_ZERO(&read_fds);
}
socket_server_socket socket_server_start(char *socket_path)
{
struct sockaddr_un local;
int len;
int socket_descriptor = socket(AF_UNIX, SOCK_STREAM, 0);
if (socket_descriptor == -1)
return (socket_server_socket) {.status = SOCKET_SERVER_START_SOCKET_FAILURE, .descriptor = -1};
local.sun_family = AF_UNIX;
strcpy(local.sun_path, socket_path);
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
if (bind(socket_descriptor, (struct sockaddr *)&local, len) == -1)
return (socket_server_socket) {.status = SOCKET_SERVER_START_BIND_FAILURE, .descriptor = -1};
if (listen(socket_descriptor, 5) == -1)
return (socket_server_socket) {.status = SOCKET_SERVER_START_LISTEN_FAILURE, .descriptor = -1};
FD_SET(socket_descriptor, &master);
fdmax = socket_descriptor;
return (socket_server_socket) {.status = 0, .descriptor = socket_descriptor};
}
socket_server_socket socket_server_wait_for_connection(socket_server_socket server)
{
read_fds = master;
select(fdmax+1, &read_fds, NULL, NULL, &tv);
for (i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, &read_fds))
{
if (i == server.descriptor)
{
// It's getting stuck here.
socket_descriptor = accept(server.descriptor, (struct sockaddr *) NULL, NULL);
if (socket_descriptor > fdmax)
fdmax = socket_descriptor;
FD_SET(socket_descriptor, &master);
return (socket_server_socket) {.status = -1, .descriptor = socket_descriptor};
} else {
return (socket_server_socket) {.status = 0, .descriptor = i};
}
}
}
return (socket_server_socket) {.status = -1, .descriptor = -1};
}
int socket_server_update(socket_server_socket client)
{
char buffer[256];
int n = recv(client.descriptor, buffer, 256, 0);
if (n < 0)
return SOCKET_SERVER_UPDATE_RECV_FAILURE;
if (send(client.descriptor, buffer, n, 0) < 0)
return SOCKET_SERVER_UPDATE_SEND_FAILURE;
close(client.descriptor);
return 0;
}
然后在我的主程序中:
socket_server_init();
socket_server_socket server = socket_server_start(SOCKET_PATH);
while (1) {
printf("wait for conn\n");
socket_server_socket client = socket_server_wait_for_connection(server);
if (client.status == 0)
{
socket_server_update(client);
}
sleep(1);
printf("%d: Log !\n", (int)time(NULL));
}
当我运行程序时,我观察到:
- “记录!”在控制台输出
- 我通过socket连接到服务器
- 我继续看到“日志!”在控制台上
- 我从客户端发送了一些数据
- 客户端看到数据回显
- “记录!”不再显示在控制台上
- 来自客户端的任何后续数据都不会回显
我希望循环继续并“记录!”继续输出,但看起来我的程序在 accept 调用时卡住了,但只是第二次。
据我了解,select 仅应在需要被接受或接收时将描述符添加到read_fds。所以似乎发生的是:
-
select将服务器的描述符添加到read_fds - 它被接受了
-
select再次将服务器描述符添加到read_fds - 没有什么可以等待
accepted 所以accept挂起
我已经验证,当调用accept 时,描述符是相同的。所以我很困惑。
我做错了什么?我确定它不应该为同一个连接第二次点击accept。
【问题讨论】:
标签: c sockets unix-socket