簡體   English   中英

在Visual C ++中接受來自客戶端(套接字編程)的連接的問題

[英]Problem in accepting connection from client (socket programming) in Visual C++

我已經用Visual C ++編寫了一個簡單的單線程客戶端服務器應用程序。 當我運行我的服務器時,我等待一段時間它接受來自客戶端的一些請求。

當我將客戶端連接到服務器時。 客戶端上的日志消息報告發送14個字節,服務器上沒有消息。 我已經編寫了一個print語句來打印控制台上服務器接受的內容,但服務器不打印任何內容。

在我看來,客戶端已連接到其他服務器。

客戶端和服務器代碼如下。

服務器代碼

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <conio.h>

#define DEFAULT_PORT        "27015"
#define DEFAULT_BUFLEN        512
#pragma comment(lib, "Ws2_32.lib")

int main() {
    WSADATA wsdata;
    int result = WSAStartup(MAKEWORD(2,2),&wsdata);
    if (result != 0){
        printf("%s","Unable to initilize windows socket\n");
        getch();
        return 1;
    }

    struct addrinfo *addrResult = NULL,hints;
    ZeroMemory(&hints, sizeof (hints));

    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    result = getaddrinfo(NULL,DEFAULT_PORT,&hints,&addrResult);
    if (result != 0){
        printf("%s","Error in getaddrInfo");
        getch();
        return 1;
    }
    SOCKET listenSocket = INVALID_SOCKET;
    listenSocket = socket(addrResult->ai_family,addrResult->ai_socktype,addrResult->ai_protocol);

    if (listenSocket == INVALID_SOCKET){
        printf("%s","Error in creating socket object\n");
        getch();
        closesocket(listenSocket);
        WSACleanup();
        return 1;
    }

    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr("127.0.0.1");
    service.sin_port = htons(27015);

    if (bind(listenSocket,addrResult->ai_addr,
        (int)addrResult->ai_addrlen) == SOCKET_ERROR){
    //if(bind(listenSocket,(SOCKADDR*) &service,
    //    sizeof(service)) == SOCKET_ERROR){

        printf("bind failed: %d\n", WSAGetLastError());
        freeaddrinfo(addrResult);
        closesocket(listenSocket);
        WSACleanup();
        getch();
        return 1;
    }
    freeaddrinfo(addrResult);
    if (listen(listenSocket,SOMAXCONN) == SOCKET_ERROR){
        printf("%s","Error in listening socket");
        getch();
        closesocket(listenSocket);
        WSACleanup();
    }
    SOCKET clientSocket = INVALID_SOCKET;
    clientSocket = accept((listenSocket,NULL,NULL);
    if (clientSocket ==  INVALID_SOCKET){
        closesocket(listenSocket);
        WSACleanup();
    }

    char recvbuf[DEFAULT_BUFLEN];
    int iRecvResult, iSendResult;
    int recvbuflen = DEFAULT_BUFLEN;

    do{
        iRecvResult = 0;
        iSendResult = 0;
        iRecvResult = recv(clientSocket,recvbuf,recvbuflen,0);
        if (iRecvResult > 0){
            printf("Bytes received: %d\n", iRecvResult);
            getch();
            // Echo the buffer back to the sender
            iSendResult = send(clientSocket, recvbuf, iRecvResult, 0);
            if (iSendResult == SOCKET_ERROR) {
                printf("send failed: %d\n", WSAGetLastError());
                closesocket(clientSocket);
                WSACleanup();
                return 1;
            }
            printf("Bytes sent: %d\n", iSendResult);
        }
        else if (iRecvResult == 0){
            printf("Connection closing...\n");
        }
        else{
            printf("recv failed: %d\n", WSAGetLastError());
            closesocket(clientSocket);
            WSACleanup();
            return 1;
        }
    }while(iRecvResult > 0);
  getch();
  return 0;
}

客戶代碼

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <conio.h>

#define DEFAULT_PORT        "27015"
#define DEFAULT_BUFLEN        512
#pragma comment(lib, "Ws2_32.lib")

int main(){
    WSADATA wsdata;
    WSAStartup(MAKEWORD(2,2),&wsdata);
    struct addrinfo *addrResult = NULL,hints;
    ZeroMemory(&hints, sizeof (hints));
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_family = AF_UNSPEC;
    int result = 0;
    if (getaddrinfo("127.0.0.1",DEFAULT_PORT,
        &hints,&addrResult)){
            printf("%s","Error in getaddrInfo\n");
            WSACleanup();
            getch();
            return 1;
    }
    SOCKET connectingSocket = INVALID_SOCKET;
    connectingSocket = socket(addrResult->ai_family,addrResult->ai_socktype,
        addrResult->ai_protocol);
    if (connectingSocket == INVALID_SOCKET){
        printf("%s","Error in creating socket\n");
        freeaddrinfo(addrResult);
        WSACleanup();
        getch();
        return 1;
    }

    if (connect(connectingSocket,addrResult->ai_addr, (int)addrResult->ai_addrlen) != 0){
        closesocket(connectingSocket);
        connectingSocket = INVALID_SOCKET;
        WSACleanup();

    }
    freeaddrinfo(addrResult);

    int recvbuflen = DEFAULT_BUFLEN;
    char *sendbuf = "this is a test";
    char recvbuf[DEFAULT_BUFLEN];

    int iResult;

    // Send an initial buffer
    iResult = send(connectingSocket, sendbuf, (int) strlen(sendbuf), 0);
    if (iResult == SOCKET_ERROR) {
        printf("send failed: %d\n", WSAGetLastError());
        closesocket(connectingSocket);
        WSACleanup();
        return 1;
    }

    printf("Bytes Sent: %ld\n", iResult);

    // shutdown the connection for sending since no more data will be sent
    // the client can still use the connectingSocket for receiving data
    iResult = shutdown(connectingSocket, SD_SEND);
    if (iResult == SOCKET_ERROR) {
        printf("shutdown failed: %d\n", WSAGetLastError());
        closesocket(connectingSocket);
        WSACleanup();
        return 1;
    }

    // Receive data until the server closes the connection
    do {
        iResult = recv(connectingSocket, recvbuf, recvbuflen, 0);
        if (iResult > 0)
            printf("Bytes received: %d\n", iResult);
        else if (iResult == 0)
            printf("Connection closed\n");
        else
            printf("recv failed: %d\n", WSAGetLastError());
    } while (iResult > 0);

    getch();
    return 0;
}

當客戶端嘗試通過增強診斷來發送時,您可以確認服務器代碼中發生的情況。 在重要時間輸出更多(例如成功的connect()accept()close() ,所有套接字錯誤,可選的send/recv流量日志文件)可能會很快指向解決方案。 確保檢查並輸出所有套接字API調用上的任何錯誤。

您可以使用netstat檢查偵聽目標端口/地址的其他系統。

我看不出任何明顯的錯誤。

嗯...在修復了明顯的語法錯誤( clientSocket = accept((listenSocket,NULL,NULL);的不匹配的開括號clientSocket = accept((listenSocket,NULL,NULL); )后,它對我來說似乎運行得相當好。在服務器上我得到:

收到的字節數:14
發送的字節數:14
連接正在關閉...

在客戶端:

發送的字節數:14
收到的字節數:14
recv失敗:10054

因此,客戶端將14個字節發送到服務器(按Enter鍵),服務器將這14個字節回顯到客戶端(再次按Enter鍵),然后服務器關閉連接。 客戶端讀取14個字節,然后在連接關閉時進一步讀取失敗。

編輯:我通過打開兩個Windows SDK命令提示符窗口來運行代碼,其中一個運行server ,另一個運行client ,這兩個都沒有特別令人興奮或不同尋常的地方。

我建議你做以下事情:

  • 為了實驗,從代碼中刪除所有getch()
  • 確保您的tcp服務器和tcp客戶端應用程序都沒有運行
  • 在Windows防火牆設置中刪除應用的所有規則
  • 在CMD shell中運行以下內容 - 您需要使GREP可用:

    netstat -a -b | grep -e“ 27015” --after = 1

如果此命令的輸出不為空 - 您將看到作為問題根源的應用程序的名稱。 否則,嘗試通過運行服務器然后 - 客戶端來重現您的問題。 如上所述(或通過tcpview程序)通過netstat命令監視服務器的狀態。 有趣的結果是什么。

Offtopic note:您的斷開序列不完整。 谷歌graceful disconnect 通常它看起來像這樣:

[ client ]發出shutdown (sd_send)並等待來自服務器的剩余數據

[ server ]如果recv ()== 0則{ send (剩余數據); 發出shutdown (sd_send); closesocket }

[ 客戶 ]收到剩余數據; 如果recv ()== 0則關閉

在客戶端中,您正在關閉發送連接:

// shutdown the connection for sending since no more data will be sent
// the client can still use the connectingSocket for receiving data
iResult = shutdown(connectingSocket, SD_SEND);
if (iResult == SOCKET_ERROR) {
    printf("shutdown failed: %d\n", WSAGetLastError());
    closesocket(connectingSocket);
    WSACleanup();
    return 1;
}

服務器檢測到斷開連接(recv返回0)並在不關閉其側面連接的情況下完成,這就是您收到錯誤100054的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM