Last active
December 24, 2022 00:53
-
-
Save muratamuu/da3e495221d8b4ce24c7 to your computer and use it in GitHub Desktop.
select()中に別スレッドからsocketをcloseした場合のテスト
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
このコード、Linuxでは動かない・・・