2016-04-26 14 views
-1

私はソケットプログラミングコードを作成しています。C++ソケットプログラミング:AcceptとRecvメソッドはプロセスをブロックしません

と私は次のようにサーバ側プログラムを実装:

#include "Common.h" 
#include "EP_Test4.h" 

int main() 
{ 
    printf("Start EP3 \n"); 

    while (1){ 
     EP_Test4 et; 
    } 

    return 0; 
} 

これはメインコードです。あなたが見ることができるように、コード行はwhileステートメント内にあります。 がある場合は、クラスが呼び出され、クラスのコンストラクタも呼び出された後、 "initEntryPoint()"メソッドが呼び出されます。 initEntryPointコードで

EP_Test4::EP_Test4(){ 

    initEntryPoint(); 
} 

、ソケット方式(InitCtrlSocket)の開始、データ受信方法及び閉鎖ソケット方法があります。

void EP_Test4::initEntryPoint() 
{ 
    printf("[Waiting Restart Signal] \n"); 
    CSocket cCtrlEpSock; 
    cCtrlEpSock.InitCtrlSocket(); 
    cCtrlEpSock.RecvRestartEPMsg(); 
    cCtrlEpSock.CloseCtrlSocket(); 
} 

そして、それらの方法

void CSocket::InitCtrlSocket(){ 

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { 
     printf("error\r\n"); 
    } 

    if ((EpCtrlServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0)   
    { 

     perror("socket error : "); 
     exit(1); 
    } 

    memset(&server_addr, 0, sizeof(server_addr)); 

    server_addr.sin_family = AF_INET; 
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY); 
    server_addr.sin_port = htons(6870); 

    if (bind(EpCtrlServerSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
    { 
     perror("bind error: "); 
     exit(1); 
    } 

    if (listen(EpCtrlServerSocket, 5)<0) 
    { 
     perror("listen error : "); 
     exit(1); 
    } 

    EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen); 
} 

void CSocket::RecvRestartEPMsg(){ 
    char arrRecvCompleteMsg[50]; 
    memset(&arrRecvCompleteMsg, 0, sizeof(arrRecvCompleteMsg)); 

    int data_len = recv(EpCtrlClientSocket, (char*)&arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0); 
    cout << "RECV CTRL MSG : " << arrRecvCompleteMsg << endl; 
} 

void CSocket::CloseCtrlSocket(){ 

    closesocket(EpCtrlServerSocket); 
    closesocket(EpCtrlClientSocket); 
    WSACleanup(); 
} 

を次のようにのように実装されているが、プログラムが実行されると、acceptメソッドとのrecv方法が待っていません。印刷されたメッセージは下の画像のように繰り返されます。

が正常に動作する(ブロックする方法で待機する)ことがあります。 なぜこれが起こるのか分かりません。 私が知っているように、acceptメソッドとrecvメソッドは "ブロッキング"メソッドです。しかし、なぜそれらのメソッドが時々ブロックされるのではないのですか?

when the program is executed

+0

を証拠はthe'accept() 'と'のrecv() 'メソッドは、「あなたは上がらない、ブロックしていないことをここではありません'recv()'の戻り値をエラーチェックします。あなたのコードは、TCPサーバーのために非常に奇妙な構造になっています。チュートリアルを参照して、受け入れられたソケットにスレッドを使用する必要があります。ここにテキストの写真を掲載して時間と帯域幅を無駄にしないでください。テキストを投稿する。 – EJP

答えて

1

あなたの問題を診断するための十分なコードを示していません。また、またはrecv()のいずれかのエラー処理であるを実行していません。 accept()が失敗し、無効なソケットをrecv()に渡している可能性があります。

私は肢に外出する予定であり、はの変数が初期化されていないとします。そうであれば、clensizeof(client_addr)より小さくなると、accept()が失敗し、clensizeof(client_addr)以上になった場合に失敗します。

accept()addrlenパラメータはIN/OUTパラメータである:addrパラメータによって指される構造体の長さを含む整数へ

addrlenは[OUT、IN]
任意ポインタ。

...

addrlenはで参照される整数は最初のスペースの量は、addrが指さ含まれています。戻り時には、返されたアドレスの実際の長さがバイト単位で格納されます。

...

パラメータaddrが通信層に知られているように、接続エンティティのアドレスで満たされる結果パラメータです。 addrパラメータの正確な形式は、通信が行われているアドレスファミリによって決まります。addrlenは値の結果のパラメータです。最初はaddrが指すスペースの量を含んでいなければなりません。リターン時には、返されるアドレスの実際の長さ(バイト単位)が格納されます。あなたが正しく入力サイズを指定しない場合

accept()は失敗します。

WSAEFAULT
addrlenはパラメータが小さすぎるまたはaddrは、ユーザーのアドレス空間の有効な部分ではありません。

代わりにこれを試してみてください:

clen = sizeof(client_addr); // <-- add this 
EpCtrlClientSocket = accept(EpCtrlServerSocket, (struct sockaddr *)&client_addr, &clen); 
if (EpCtrlClientSocket < 0) // <-- add this 
{ 
    perror("accept error : "); 
    exit(1); 
} 

void CSocket::RecvRestartEPMsg(){ 
    char arrRecvCompleteMsg[50];  
    int data_len = recv(EpCtrlClientSocket, arrRecvCompleteMsg, sizeof(arrRecvCompleteMsg), 0); 
    if (data_len > 0) // <-- add this 
    { 
     cout << "RECV CTRL MSG : "; 
     cout.write(arrRecvCompleteMsg, data_len); 
     cout << endl; 
    } 
    else 
     cout << "RECV CTRL ERR : " << endl; 
} 
関連する問題