Skip to content

Instantly share code, notes, and snippets.

@muratamuu
Last active December 24, 2022 00:53
Show Gist options
  • Save muratamuu/da3e495221d8b4ce24c7 to your computer and use it in GitHub Desktop.
Save muratamuu/da3e495221d8b4ce24c7 to your computer and use it in GitHub Desktop.
select()中に別スレッドからsocketをcloseした場合のテスト
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <errno.h>
#include <thread>
#include <unistd.h>
static void client(int s);
static void server(int ss);
int main(int argc, char **argv)
{
// サーバを接続待ちする
int ss = socket(AF_INET, SOCK_STREAM, 0);
auto t1 = std::thread([ss](){ server(ss); });
sleep(1);
// クライアントを接続開始する
int s = socket(AF_INET, SOCK_STREAM, 0);
auto t2 = std::thread([s](){ client(s); });
sleep(1);
// 強制的に外部(main thread)からクライアントのソケットを切断する
printf("[main] FORCE CLOSE (client socket)\n");
close(s);
// ちゃんとスレッドを回収する
t1.join();
printf("[main] server thread joined\n");
t2.join();
printf("[main] client thread joined\n");
return 0;
}
void client(int s)
{
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_port = htons(30000);
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
perror(strerror(errno));
close(s);
return;
}
printf("[client] connect OK %d\n", s);
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(s, &rfd);
printf("[client] waiting select ...\n");
if (select(s+1, &rfd, NULL, NULL, NULL) < 0) {
// 外部から強制的にsを閉じられると、BAD DISCRIPTORでちゃんとselectを抜ける
printf("[client] select error %s\n", strerror(errno));
close(s);
return;
}
printf("[client] select OK\n");
char buffer[1];
int sz = recv(s, buffer, 1, 0);
printf("[client] recv size %d\n", sz);
close(s);
return;
}
void server(int ss)
{
struct sockaddr_in sa;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_ANY;
sa.sin_port = htons(30000);
if (bind(ss, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
perror(strerror(errno));
close(ss);
return;
}
if (listen(ss, 3) < 0) {
perror(strerror(errno));
close(ss);
return;
}
fd_set rfd;
FD_ZERO(&rfd);
FD_SET(ss, &rfd);
printf("[server] waiting accept select ...\n");
if (select(ss+1, &rfd, NULL, NULL, NULL) < 0) {
printf("[server] accept select error %s\n", strerror(errno));
close(ss);
return;
}
int s = accept(ss, NULL, 0);
if (s < 0) {
perror(strerror(errno));
close(ss);
return;
}
close(ss);
printf("[server] accept OK %d\n", s);
FD_ZERO(&rfd);
FD_SET(s, &rfd);
printf("[server] waiting recv select ...\n");
if (select(s+1, &rfd, NULL, NULL, NULL) < 0) {
printf("[server] recv select error %s\n", strerror(errno));
close(s);
return;
}
// クライアント側が閉じられると対抗のserver側は成功(読み出しデータあり)
// で返ってくる
printf("[server] select OK\n");
char buffer[1];
int sz = recv(s, buffer, 1, 0);
printf("[server] recv size %d\n", sz); // 確かにサイズ0 (つまり切られた)
close(s);
return;
}
@muratamuu
Copy link
Author

このコード、Linuxでは動かない・・・

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment