質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

2回答

9128閲覧

[C++]selectで10038 (WSAENOTSOCK)

takuan_no_hito

総合スコア27

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2017/08/17 14:54

編集2017/08/18 02:04

TCP/IPネットワークプログラムを参考にしながらサーバープログラムを作ろうと試みているのですが、絶賛躓き中です。

問題点

  • 1つのクライアントを下記のサーバープログラムに接続後、select関数がエラー(return value -1)となり、ノータイムで関数を抜ける(struct timevalは1秒に設定されているにも関らず)
  • なおかつ、select直後のerrnoは0である(確認済み)
  • クライアント接続前は一秒毎にselect()のreturn value が 0で正常に動作しているように見えます。

nfdsの値が問題かと思い、最大値にしてみたりもしましたが上手くいきません。何が問題なのでしょうか?


追記

  • Harahiraさんにより、errnoにエラーを吐かず、WSAGetLastError()でエラーを取得できるとのことで、取得したところ、下記の様なエラーがでました。

10038 (WSAENOTSOCK):指定されたディスクリプタはソケットではありません。

C++

1 2#include <stdio.h> 3#include <tchar.h> 4#include <winsock2.h> 5#include <ws2tcpip.h> 6 7int main() 8{ 9 //適切なポート番号を生成する 10 int port = 7788; 11 12 13 //ポート番号及びソケット 14 int srcSocket;//自分 15 struct sockaddr_in srcAddr; 16 17 int dstSocket[10];//相手 18 struct sockaddr_in dstAddr[10]; 19 int dstAddrSize[10]; 20 for (int i = 0; i < 10; i++) { 21 dstAddrSize[i] = sizeof(dstAddr[i]); 22 dstSocket[i] = -1; 23 } 24 25 //受信用buffer 26 char buffer[1024]; 27 28 //Windowsの場合 29 WSADATA data; 30 WSAStartup(MAKEWORD(2, 0), &data); 31 //sockaddr_in 構造体のセット 32 memset(&srcAddr, 0, sizeof(srcAddr)); 33 srcAddr.sin_port = htons(port); 34 srcAddr.sin_family = AF_INET; 35 srcAddr.sin_addr.s_addr = htonl(INADDR_ANY); 36 37 //ソケットの生成(ストリーム型) 38 srcSocket = socket(AF_INET, SOCK_STREAM, 0); 39 //ソケットのバインド 40 bind(srcSocket, (struct sockaddr *)&srcAddr, sizeof(srcAddr)); 41 //接続の許可 42 listen(srcSocket, 1); 43 44 45 // 1秒でタイムアウトするようにします 46 struct timeval tv; 47 tv.tv_sec = 1; 48 tv.tv_usec = 0; 49 //受信中の数 50 int user_len = 0; 51 52 fd_set rfds, efds; 53 int nfd = srcSocket; 54 for (;;) {//無限ループ 55 FD_ZERO(&rfds); 56 FD_ZERO(&efds); 57 FD_SET(srcSocket, &rfds); 58 for (int j = 0; j < user_len; j++) { 59 FD_SET(dstSocket[j], &rfds); 60 FD_SET(dstSocket[j], &efds); 61 if (dstSocket[j] > nfd)nfd = dstSocket[j]; 62 } 63 if (select(nfd + 1, &rfds, NULL, &efds, &tv) < 0) { 64 //errno==EINTRのときはシグナルを受信したとき 65 if (errno != EINTR) { 66 continue; 67 } 68 } 69 70 if (FD_ISSET(srcSocket, &rfds)) {//新規接続 71 int asock; 72 struct sockaddr_in caddr; 73 int caddr_len; 74 75 //アクセスの許可 76 caddr_len = sizeof(caddr); 77 if (asock = accept(srcSocket, (struct sockaddr *)&caddr, &caddr_len) < 0) { 78 if (errno == EINTR)continue; 79 80 printf("error with accept\n"); continue; 81 } 82 printf("USER accepted\n"); 83 84 //登録 85 dstAddr[user_len] = caddr; 86 dstAddrSize[user_len] = caddr_len; 87 dstSocket[user_len] = asock; 88 user_len++; 89 } 90 for (int j = 0; j < user_len; j++) { 91 int psize = 0; 92 //一つ一つ受信可能か確かめる 93 if (FD_ISSET(dstSocket[j], &rfds)) { 94 if ((psize = recv(dstSocket[j], buffer, 1024, 0)) <= 0) { 95 //途中で接続切れ 96 printf("disconnect in receive\n"); 97 continue; 98 } 99 else if (psize < 1024) { 100 buffer[psize] = '\0'; 101 } 102 else { 103 buffer[1024] = '\0'; 104 psize = 1023; 105 } 106 printf("受信ワード:%s", buffer); 107 //本人にのみとりあえず返信する 108 send(dstSocket[j], buffer, sizeof(char) * (psize + 1), 0); 109 continue; 110 } 111 if (FD_ISSET(dstSocket[j], &efds)) { 112 printf("disconnect in efds\n"); 113 } 114 } 115 } 116 //Windowsでの終了設定 117 WSACleanup(); 118 119 return 0; 120} 121 122

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takano32

2017/08/17 19:37

カテゴリに `Socket.IO` とありますが、 `Socket.IO` は Node.js のモジュールです。
takuan_no_hito

2017/08/18 01:27

ありがとうございます。修正しました。
guest

回答2

0

Winsockのselectは、エラー発生時にerrnoを設定しません。WSAGetLastErrorにてエラーを取得してください。
select function

投稿2017/08/18 01:18

Harahira

総合スコア243

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuan_no_hito

2017/08/18 01:27

回答ありがとうございます。 そうなのですね! WSAGetLastError()にてエラーコードを取得したところ、 10038 (WSAENOTSOCK):指定されたディスクリプタはソケットではありません。 とのことでした。 自分でももう少し調べられそうです、本当にありがとうございます!
guest

0

ベストアンサー

接続が切れた時にuser_lenがそのままになっているから無効なソケットをFD_SETしてるんでエラーになってるんじゃないかな?
dstSocketの何番目がいつ切れるかわからないからuser_lenで数を記憶するよりも配列を全部-1とか無効な値に初期化しておいて、接続が切れたらそれに戻してFD_SETをしないようにしないといけないと思います。

[追記]
わかった、別件でバグってますね。
()が漏れてるんでasockが常に1になってると思います。

if ((asock = accept(srcSocket, (struct sockaddr *)&caddr, &caddr_len)) < 0) {

こうです。

投稿2017/08/17 15:48

編集2017/08/18 03:03
toki_td

総合スコア2850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takuan_no_hito

2017/08/18 01:17

回答ありがとうございます。 はい、その問題に関してはこちらでも認識していましたが、当方で抱えている問題が、 「1つ目のクライアント接続時」の問題であったため、放置していました。 また、接続切れのときはdstSocketの値を-1にし、FD_SETしないようにプログラムを修正しましたが、やはり解決しませんでした。
takuan_no_hito

2017/08/18 04:10

その通りでした…まさかこのような初歩的なミスとは思わず色々と空回りしていました;; ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問