サーバー側のプログラムのlistenについて – プログラミング – Home

サーバー側のプログラムのlistenに...
 
通知
すべてクリア

[解決済] サーバー側のプログラムのlistenについて


秋桜
 秋桜
(@秋桜)
ゲスト
結合: 20年前
投稿: 20
Topic starter  

皆様に質問がございます。私は今、ネットワークプログラムの入り(?)である
チャットプログラムを作成していて、一番初めの通信がうまくいくところまで
こじつけることができました。接続は受信一回ごとにソケットを破棄して、毎回作り
直せばいいかな?と考えたので、Winproc()でlistenThreadと言うスレッドを毎回作って
受信しています。しかし、サーバー側のプログラムを起動したままもう一度受信待ちを
しようとするとなぜかうまくいきません。どうやらbind()がエラーを返してきている
ようなのですが、いまいちどうやったら直るのかが分かりません。私個人は、前回
作ったスレッドがまだ残って悪さしているのかな?と考えてもいるのですがnetstatで
見る限りそのようなこともなさそうなさそうです。繰り返しになってしまいますが
本当によく分かりません。ご助言のほどよろしくお願いいたします。

#include <windows.h>
#include <winsock.h>
#include <stdlib.h>
#include <stdio.h>

#include recv.h
#include resource.h

void listenThread(HWND hWnd){

char Buffer[128] ;
char str[200];
int rVal, fromlen;
SOCKADDR_IN local, from ;
WSADATA wsaData ;
SOCKET listen_socket ;
SOCKET msgsock ;

do{ // スレッドを抜けるための大枠

// ソケットの初期化
if((rVal = WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) ) != 0 )
{
MessageBox( hWnd, ソケットの初期化に失敗しまし
た, ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// SOCKADDR_IN構造体の設定
local.sin_family = AF_INET ;
local.sin_addr.s_addr = INADDR_ANY ;
local.sin_port = htons( port ) ;

// ソケット生成
listen_socket = socket( AF_INET, SOCK_STREAM, 0 ) ; // TCP
socket
if( listen_socket == INVALID_SOCKET ) {
MessageBox( hWnd, ソケットの作成に失敗しまし
た, ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup();
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// 生成したソケットにバインド
if( bind( listen_socket, (struct sockaddr*)&local, sizeof
(local) ) == SOCKET_ERROR) {
MessageBox( hWnd, IPアドレスとポートの関連付けに失
敗しました, ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup();
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// listen
if( listen( listen_socket, 5 ) == SOCKET_ERROR ) {
MessageBox( hWnd, 受信待ちに失敗しました, ソケッ
トエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}
wsprintf( (LPSTR)&str, ポート番号%dをlistning中..., port);
drawClient(hWnd,memdc,str,hFont,CharHeight);

// accept
fromlen = sizeof( from ) ;
msgsock = accept( listen_socket, (struct sockaddr*)&from,
&fromlen ) ;
if( msgsock == INVALID_SOCKET ) {
MessageBox( hWnd, 接続に失敗しました, ソケットエ
ラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}
wsprintf( (LPSTR)&str, \nサーバ=%s, ポート番号=%dに接
続.\n\n,inet_ntoa(from.sin_addr), htons(from.sin_port));
drawClient(hWnd,memdc,str,hFont,CharHeight);

// 受信永久ループ
while( TRUE ) {
// メッセージを受信
rVal = recv( msgsock, Buffer, sizeof( Buffer ), 0 );
if( rVal == SOCKET_ERROR ) {
MessageBox( hWnd, 受信に失敗しました, ソ
ケットエラー, MB_OK | MB_ICONEXCLAMATION);
break ;
}
if( rVal == 0 ) {
drawClient(hWnd,memdc,接続が終了しまし
た,hFont,CharHeight);
break ;
}

// 「.」なら終了
if( Buffer[0] == '.' ){
drawClient(hWnd,memdc,接続が終了しまし
た,hFont,CharHeight);
break ;
}

// メッセージを表示してループを続ける
Buffer[rVal] = '\0' ;
drawClient(hWnd,memdc,Buffer,hFont,CharHeight);
}

}while(FALSE);

// 終了処理
shutdown(msgsock,2); // SD_BOTH 送受信を無効にする
closesocket( msgsock ) ;
PostMessage(hWnd, ID_EXIT_THREAD, 0, 0);
WSACleanup() ;

}


引用未解決
トピックタグ
秋桜
 秋桜
(@秋桜)
ゲスト
結合: 20年前
投稿: 20
Topic starter  

すみません、ソース見にくいので再び晴らせていただきます。

#include <windows.h>
#include <winsock.h>
#include <stdlib.h>
#include <stdio.h>

#include recv.h
#include resource.h

void listenThread(HWND hWnd){

char Buffer[128] ;
char str[200];
int rVal, fromlen;
SOCKADDR_IN local, from ;
WSADATA wsaData ;
SOCKET listen_socket ;
SOCKET msgsock ;

do{
// ソケットの初期化
if((rVal = WSAStartup( MAKEWORD( 1, 1 ), &wsaData ) ) != 0 )
{
MessageBox( hWnd, ソケットの初期化に失敗,
              ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// SOCKADDR_IN構造体の設定
local.sin_family = AF_INET ;
local.sin_addr.s_addr = INADDR_ANY ;
local.sin_port = htons( port ) ;

// ソケット生成
listen_socket = socket( AF_INET, SOCK_STREAM, 0 ) ;
if( listen_socket == INVALID_SOCKET ) {
MessageBox( hWnd, ソケットの作成に失敗,
               ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup();
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// 生成したソケットにバインド
if( bind( listen_socket, (struct sockaddr*)&local,
          sizeof(local) ) == SOCKET_ERROR) {
MessageBox( hWnd, 関連付けに失敗,
               ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup();
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}

// listen
if( listen( listen_socket, 5 ) == SOCKET_ERROR ) {
MessageBox( hWnd, 受信待ちに失敗,
               ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}
wsprintf( (LPSTR)&str, ポート番号%dをlistning中..., port);
drawClient(hWnd,memdc,str,hFont,CharHeight);

// accept
fromlen = sizeof( from ) ;
msgsock = accept( listen_socket, (struct sockaddr*)&from,
          &fromlen ) ;
if( msgsock == INVALID_SOCKET ) {
MessageBox( hWnd, 接続に失敗,
               ソケットエラー, MB_OK | MB_ICONEXCLAMATION);
WSACleanup() ;
PostMessage(HWND_BROADCAST, ID_EXIT_THREAD, 0, 0);
break;
}
wsprintf( (LPSTR)&str,
          \nサーバ=%s, ポート番号=%dに接続.\n\n,
          inet_ntoa(from.sin_addr), htons(from.sin_port));
drawClient(hWnd,memdc,str,hFont,CharHeight);

// 受信永久ループ
while( TRUE ) {
// メッセージを受信
rVal = recv( msgsock, Buffer, sizeof( Buffer ), 0 );
if( rVal == SOCKET_ERROR ) {
MessageBox( hWnd, 受信に失敗,
                    ソケットエラー,
                    MB_OK | MB_ICONEXCLAMATION);
break ;
}
if( rVal == 0 ) {
drawClient(hWnd,memdc,
                   接続の終了,hFont,CharHeight);
break ;
}

// 「.」なら終了
if( Buffer[0] == '.' ){
drawClient(hWnd,memdc,
                   接続の終了,hFont,CharHeight);
break ;
}

// メッセージを表示してループを続ける
Buffer[rVal] = '\0' ;
drawClient(hWnd,memdc,Buffer,hFont,CharHeight);
}

}while(FALSE);

// 終了処理
shutdown(msgsock,2); // SD_BOTH 送受信を無効にする
closesocket( msgsock ) ;
PostMessage(hWnd, ID_EXIT_THREAD, 0, 0);
WSACleanup() ;

}


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

頭から全部スレッド化するんじゃなくて、bind は一回でいいと思います。
ソケットの初期化~listen までを一回だけ行い、accept 待ちスレッドを立てる。
accept から戻ったら、受信スレッドを立てる、で。


返信引用
九条
 九条
(@九条)
ゲスト
結合: 20年前
投稿: 4
 

listenがエラーになるのは単純にlistenソケットを閉じてないからなのでは?
というか、ループごとに毎回WSAStartupをするのは問題があると思います。
(WSACleanupと対応していないし)

根本的な問題としてlistenの使い方を勘違いしていると思います。
bind → ソケットを固定ポートと関連付ける
listen → 指定ソケットで接続を受け付けることを通知する
accept → クライアントからの接続を実際に受け付ける
なので、リッスンしたらそのソケットをずっと利用してacceptでクライアントの
接続を待ちつづけます。
具体的には(エラー処理を除く)

// ソケット作成
listenSocket = socket(AF_INET, SOCK_STREAM, 0);

// ソケットを指定ポートに関連付ける
bind(listenSocket, (sockaddr*)&local, sizeof(local));

// ソケットがリッスンすることを通知
listen(listenSocket, 5);

while(1) {
// 新規クライアントの受付待ち
msgsock = accept(listenSocket, (struct sockaddr*)&from, &fromlen );
while(1) {
// クライアントとの通信
...
}
// クライアントを切断
closesocket(msgsock);
}
closesocket(listenSocket);

という流れになります。


返信引用
九条
 九条
(@九条)
ゲスト
結合: 20年前
投稿: 4
 

あ、シャノンさんが完結にされてましたね(^^;;;


返信引用
秋桜
 秋桜
(@秋桜)
ゲスト
結合: 20年前
投稿: 20
Topic starter  

九条様、シャノン様、いろいろご指摘ありがとうございました。
言われたとおり修正したら、何の問題もなくなりました。
本当にありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました