0

だから私はミニチャットアプリを作成しようとしています.ソケットプログラミングとスレッドについて1つか2つのことを理解するためだけに、私はc ++ Mfcでそれをやっています. netstatでそれを)しかし、sendおよびrecv関数に関しては、それがどのように行われるべきかをよく理解できません.クライアントアプリからメッセージを送信しますが、サーバーはそれを受信して​​いないようです.

サーバーのソースコード:

int RcvThread();
SOCKET s;
void CChat_ServerDlg::OnBnClickedButton2()
{

WSADATA w;

int error = WSAStartup ( 0x0202,&w);
if(error)
{
    OnCancel();
}
 if (w.wVersion != 0x0202) 
{
    WSACleanup ();
    OnCancel();
}
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(DEFAULT_PORT);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP);
     if (s == INVALID_SOCKET)
{
    OnCancel();
}
 if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
{

    OnCancel();
}
listen (s, SOMAXCONN);
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE) RcvThread, NULL, NULL, NULL);

int buffsize = 1024;
char msg[1024] = "a";
int marker;
}

    int RcvThread()
    {
char sbuffer[256];

char buffer[sizeof(sbuffer)] = {0};

for(;; )
{

    if(recv(s, buffer, sizeof(sbuffer), NULL) > 0)
    {
        memcpy(&sbuffer, buffer, sizeof(sbuffer));
        MessageBox(hnd,sbuffer,"message",NULL);
    }
}

return 0;
    }

クライアントのソースコード:

SOCKET s;
void CChat_ClientDlg::OnBnClickedOk()
{

WSADATA wsadata;

int error = WSAStartup(0x0202,&wsadata);

 if (error)
{
    MessageBox("Error","ERRR");

    OnCancel();
}


if (wsadata.wVersion != 0x0202) 
{
    WSACleanup ();
    OnCancel();
}

SOCKADDR_IN target;

target.sin_family = AF_INET;
target.sin_port = htons(3124);
target.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (s == INVALID_SOCKET)
{
    OnCancel();
}

   if (connect(s, (SOCKADDR *)&target, sizeof(target)) == SOCKET_ERROR)
{
    OnCancel();
}
}

ボタン送信メッセージ:

void CChat_ClientDlg::OnBnClickedButton2()
{
char* Msg = new char[256];
Msg = "abdouabdouabdou";
send(s,Msg,256,NULL);
}
4

2 に答える 2

2

ソケットの基本的な概念がありません。リッスン ソケット (コード内の s) は、接続要求を受け入れるために使用されます。データの送受信には使用しません。そのために別のソケットを作成する必要があります。ドキュメントとサンプルをさらに研究する必要があります。1 つのソースは次のとおりです。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms738545(v=vs.85).aspx

また、あなたのスレッドは不適切です。CreateThread を使用する場合、スレッド関数は CreateThread に指定された署名と一致する必要があります。ただし、MFC アプリでは、CreateThread の代わりに AfxBeginThread を使用する必要があります。

于 2013-10-26T13:26:32.630 に答える
1

まず、 send() と recv() がパケットを送受信すると信じているはよくある誤解です。TCP を使用する場合 (チャット プログラムでは TCP を使用する必要があります)、recv() は 0 から指定したバッファ制限までの任意のバイト数を返すことができます。したがって、256 バイトを送信する場合、recv() 関数はこれをメッセージの 2 つ、3 つ、またはそれ以上のフラグメントに分割するか、最初のメッセージの終わりと 2 番目のメッセージの始まりを返すことができます。よく行われるのは、メッセージの最初の n バイト (n はメッセージの最大サイズによって異なります) がメッセージの長さを示すことです。プロトコルを 256 バイトのメッセージ長に制限しているため、1 バイトで十分です。最初のバイトを受信したら、メッセージと同じ大きさのメッセージ バッファを割り当て、メッセージ全体を受信するまで、recv() を受信ループに入れます。受信バッファなどへのオフセットを少し調整する必要があります。

次に、bind()/listen()/accept() システムがどのように機能するかをよく理解していませんでした。listen() 関数は、ソケットを新しいクライアントをリッスンするパッシブ モードに設定します。accept() は最終的に新しいクライアントへの接続を確立し、クライアントとの通信に使用される新しいソケットを返します。元の (リッスン) ソケットは、新しいクライアントをリッスンし続けます。

3 番目に、送信関数が char-buffers を正しく処理しません。私の提案に関して少し修正しました(メッセージの最初のバイトは、次のメッセージの長さを示しています):

void CChat_ClientDlg::OnBnClickedButton2()
{
  std::string myMessage = "abdouabdouabdou";
  unsigned char buffer[256];
  buffer[0] = (unsigned char)myMessage.length();
  memcpy(buffer+1, myMessage.c_str(), std::min(myMessage.length(), 255));
  send(s, buffer, 256, NULL);
}

send() は送信されたバイト数を返しますが、これはバッファのサイズよりも小さい可能性がありますが、そのような小さなメッセージではまれなケースですが、そのメソッドでさえ正しくありません。

于 2013-10-26T13:37:46.420 に答える