2016-11-16 14 views
0

クライアントがメッセージを受信できない、またはサーバーが送信できないことを除いて、ここですべてうまくいっています。 私は本当に少し時間があるので、私はもうこの問題を処理しようとすることはできませんので、私はあなたに回っています。あなたが知っている必要があるかもしれないと思うのは、サーバーは私のネットワークの下にあり、クライアントは私の学校ネットワークの下にあります。 P.P.私はNATの背後にいるので、サーバーのための異なるIPがあります。問題はありません。Cソケット - recv:ピアによって接続がリセットされました

クライアントコード

const char* IPSERVER = "87.21.70.136"; 

int main(int argc, char *argv[]){ 

struct addrinfo hints, *serverInfo; 
int s; 

memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version 
hints.ai_socktype = SOCK_STREAM; 

if(getaddrinfo(IPSERVER, "50", &hints, &serverInfo) != 0){ 
    printf("Errore getaddrinfo(). Chiusura...\n"); 
    exit(-1); 
} 

s = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol); 
printf("Porta: %d\n", ((struct sockaddr_in *) serverInfo->ai_addr)->sin_port); 

if(connect(s, serverInfo->ai_addr, serverInfo->ai_addrlen) < 0) 
    perror("Errore connect()"); 

char buf[2000]; 
int bytes_rec; 
if((bytes_rec = recv(s, buf, sizeof buf, 0)) < 0) 
    perror("Errore recv"); 
printf("%s\n",buf); 
close(s); 

return 0; 

} 

Serverコード

struct sockaddr_storage clientAddr; 
socklen_t addrSize; 
struct addrinfo hints, *myInfo; 
int s, newS; 

memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever 
hints.ai_socktype = SOCK_STREAM; 

if(getaddrinfo("192.168.1.2", "50", &hints, &myInfo) < 0) 
    perror("Errore getaddrinfo()"); 
printf("Porta: %d\n", ((struct sockaddr_in *) myInfo->ai_addr) -> sin_port); 
s = socket(myInfo->ai_family, myInfo->ai_socktype, myInfo->ai_protocol); 
if(s < 0) 
    perror("Errore socket()"); 
printf("Socket stabilita.\n"); 
if(bind(s, myInfo->ai_addr, myInfo->ai_addrlen) < 0) 
perror("Errore bind()"); 
printf("Porta creata.\n"); 
if(listen(s, 5) < 0) 
    perror("Errore listen()"); 
printf("Server in ascolto...\n"); 
addrSize = sizeof clientAddr; 
if((newS = accept(s, (struct sockaddr *)&clientAddr, &addrSize) < 0)) 
    perror("Errore accept()"); 
printf("Invio messaggio in corso...\n"); 
char *msg = "ciao, mi vedi?"; 
int len, bytes_sent; 
len = strlen(msg); 
if((bytes_sent = send(newS, msg, len, 0)) < 0) 
    perror("Errore send()"); 
printf("Messaggio inviato.\n"); 
closesocket(newS); 
closesocket(s); 
WSACleanup(); 

return 0; 

} 

クライアント出力

Porta: 12800 
Errore recv: Connection reset by peer 

サーバー出力

Porta: 12800 
Socket stabilita. 
Porta creata. 
Server in ascolto... 
Invio messaggio in corso... 
Errore send(): No error 
Messaggio inviato. 

Process returned 0 (0x0) execution time : 4.789 s 
Press any key to continue. 
+0

'sin_port'値を印刷するには、')( 'ntohsを使用する必要があります。 12800はネットワークのバイトオーダーで表現されるので、それを印刷してからホストバイトオーダーにしてください。また、 'recv()'はバッファをヌル終了しないので、手動で行うか、 '%。* s'を使うのが良いでしょう。' bytes_rec'を 'printf()'に渡すことができます。 –

+0

ここでの本当の問題は、 'send()'エラーの後に 'エラーなし'を出力する 'perror()'です。私はより多くのファイアウォールの問題を疑う、あなたの[同じコードで前の質問](http://stackoverflow.com/questions/40600160/c-sockets-cannot-bind-server-public-ip)。注意システムコールでエラーが発生した場合は、まるで起こっていないかのように続行することはほとんど不可能です。 'socket()、listen()、bind()、connect()、accept()'のエラーはこのコードにとって致命的です。 – EJP

+0

ありがとうございます。私は明日試してみるよ。 – UrbiJr

答えて

1

サーバーのコードは明らかにサーバーがWindows上で実行されている意味のWinSock APIを使用しています。

Windowsのソケットハンドルは符号なしの値なので、intは間違ったデータ型です。代わりにSOCKETタイプを使用する必要があります。 socket()accept()の戻り値を再びINVALID_SOCKET定数と比較してください。

ソケット作成エラーを無視し、無効なソケットをsend()recv()に渡すと、エラーが発生する可能性があります。

perror()は、errnoで動作しますが、これはWinSock(および一般的なWin32 API)では使用しません。これは、が0であるため、send()が失敗した後に"no error"メッセージを説明します。WinSock関数が失敗したときに、代わりにWSAGetLastError()を使用してWinSockエラーコードを取得する必要があります。

ということで、このサーバのコードを試してみてください。

void psocketerror(const char *msg, int err) 
{ 
    fprintf(stderr, "%s: %d\n", msg, err); 
} 

void psocketerror(const char *msg) 
{ 
    psocketerror(msg, WSAgetLastError()); 
} 

int main(int argc, char *argv[]) 
{ 
    struct sockaddr_storage clientAddr; 
    socklen_t addrSize; 
    struct addrinfo hints, *myInfo; 
    SOCKET s, newS; 
    int err; 

    WSADATA wsa; 
    err = WSAStartup(MAKEWORD(2, 0), &wsa); 
    if (err != 0) { 
     psocketerror("Errore WSAStartup()", err); 
     return 1; 
    } 

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_INET; 
    hints.ai_socktype = SOCK_STREAM; 

    if ((err = getaddrinfo("192.168.1.2", "50", &hints, &myInfo)) < 0) { 
     psocketerror("Errore getaddrinfo()", err); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Porta: %d\n", ntohs(((struct sockaddr_in *)(myInfo->ai_addr))->sin_port)); 

    s = socket(myInfo->ai_family, myInfo->ai_socktype, myInfo->ai_protocol); 
    if (s == INVALID_SOCKET) { 
     psocketerror("Errore socket()"); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Socket stabilita.\n"); 

    if (bind(s, myInfo->ai_addr, myInfo->ai_addrlen) < 0) { 
     psocketerror("Errore bind()"); 
     closesocket(s); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Porta creata.\n"); 

    if (listen(s, 5) < 0) { 
     psocketerror("Errore listen()"); 
     closesocket(s); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Server in ascolto...\n"); 

    addrSize = sizeof clientAddr; 
    newS = accept(s, (struct sockaddr *)&clientAddr, &addrSize) 
    if (newS === INVALID_SOCKET) { 
     psocketerror("Errore accept()"); 
     closesocket(s); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Invio messaggio in corso...\n"); 

    char *msg = "ciao, mi vedi?"; 
    int len, bytes_sent; 
    len = strlen(msg); 

    if ((bytes_sent = send(newS, msg, len, 0)) < 0) { 
     psocketerror("Errore send()"); 
     closesocket(newS); 
     closesocket(s); 
     WSACleanup(); 
     return 1; 
    } 

    printf("Messaggio inviato.\n"); 

    closesocket(newS); 
    closesocket(s); 

    WSACleanup(); 

    return 0; 
} 
+0

ありがとうございます。私は明日試してみるよ。 – UrbiJr

+0

私はあなたのコードを試してみました、ありがとう。 Obvはfprintfでprintfsを変更するだけでした。クライアントについては、%で気づいた。* sは%sでランダムな文字を出力し、\ 0で配列を手動で終了することなく、通常受け取った文字列を出力します。ただ言って。 – UrbiJr

+0

'%。* s'は、正しく使用するとうまく動作します。例えば、' printf( "%。* s \ n"、bytes_rec、buf); '。 '%s 'の精度を指定すると' printf() 'に印刷する文字の最大数を知らせるので、バッファはNULLで終了する必要はありません。 '*'は単にフォーマット文字列の代わりに引数リストから精度値を得るように 'printf()'に指示します。 '%s'の精度を指定しない場合、バッファはヌル文字で終了する必要があります。そうでない場合、バッファに埋め込まれたヌル文字が含まれていない場合は、バッファの境界を超えて周囲のメモリからデータを出力します。 –

関連する問題