2015-11-05 78 views
0

我正在寫套接字編程,一部分先發送然後接收,一部分是接收然後發送。Cpp socket - TCP傳輸(用同一端口發送然後接收)

的工作方案是這樣的:

的ThreadA:發送到端口8000->關閉套接字 - >獲得MyPort上(門),我送 - >聽我的端口(門)

ThreadB :監聽端口8000 - >獲取該端口接收(門) - >關閉套接字 - >送包到同一個端口(端口A)

std::thread ThreadA,ThreadB; 
long share_port=8000; 
char share_addr[INET_ADDRSTRLEN]="127.0.0.1"; 

void send_then_receive(); 
void receive_then_send(); 


void send_then_receive(){ 
    long myport = -1, receiver_port = share_port; 
    SOCKET receive_then_send_A_Socket,receive_then_send_A_Socket_b,receive_then_send_B_Socket; 

    //- Send to who i want 
    struct sockaddr_in receive_then_send_B_Addr; 
    receive_then_send_B_Addr.sin_family = AF_INET; 
    inet_pton(AF_INET, share_addr, &receive_then_send_B_Addr.sin_addr.s_addr); 
    receive_then_send_B_Addr.sin_port = htons((u_short)receiver_port); 
    receive_then_send_B_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    while (connect(receive_then_send_B_Socket, (struct sockaddr *)&receive_then_send_B_Addr, sizeof(sockaddr_in)) == SOCKET_ERROR){ 
     printf("\nConnect Fail in first response| Fail Code:%i\n", WSAGetLastError()); 
    } 
    send(receive_then_send_B_Socket, "4321", 5, 0); 
    printf("[1]The port I want to send to:%ld\n",receiver_port); 

    //- Check My Port 
    socklen_t checkport_adr_len = sizeof(receive_then_send_B_Addr); 
    if (getsockname(receive_then_send_B_Socket, (struct sockaddr *)&receive_then_send_B_Addr, &checkport_adr_len) == 0){ 
     myport = ntohs(receive_then_send_B_Addr.sin_port); 
     printf("[1]MyPort Check:%ld\n", myport); 
    } 
    close(receive_then_send_B_Socket); 



    //- Then Recive 
    sockaddr_in *receive_then_send_A_Addr = new sockaddr_in; 
    receive_then_send_A_Addr->sin_family = AF_INET; 
    receive_then_send_A_Addr->sin_addr.s_addr = INADDR_ANY; 
    receive_then_send_A_Addr->sin_port = htons((u_short)myport); 
    receive_then_send_A_Socket = socket(AF_INET, SOCK_STREAM, 0); 
    bind(receive_then_send_A_Socket, (struct sockaddr *)receive_then_send_A_Addr, sizeof(struct sockaddr_in)); 
    listen(receive_then_send_A_Socket, 1); 
    std::this_thread::sleep_for(std::chrono::milliseconds(1000)); 
    receive_then_send_A_Socket_b = accept(receive_then_send_A_Socket, 0, 0); 
    char* buffer_A= new char[100]; 
    recv(receive_then_send_A_Socket_b, buffer_A, 100, 0); 
    printf("[1]What I then receive: %s\n",buffer_A); 

    close(receive_then_send_A_Socket); 
    close(receive_then_send_A_Socket_b); 


} 
void receive_then_send(){ 
    long myport = -1, receiver_port = -1; 
    SOCKET receive_then_send_A_Socket,receive_then_send_A_Socket_b,receive_then_send_B_Socket; 

    //- First Recive 
    sockaddr_in *receive_then_send_A_Addr = new sockaddr_in; 
    receive_then_send_A_Addr->sin_family = AF_INET; 
    receive_then_send_A_Addr->sin_addr.s_addr = INADDR_ANY; 
    receive_then_send_A_Addr->sin_port = htons((u_short)share_port); 
    receive_then_send_A_Socket = socket(AF_INET, SOCK_STREAM, 0); 
    bind(receive_then_send_A_Socket, (struct sockaddr *)receive_then_send_A_Addr, sizeof(struct sockaddr_in)); 
    listen(receive_then_send_A_Socket, 1); 
    receive_then_send_A_Socket_b = accept(receive_then_send_A_Socket, 0, 0); 
    char* buffer_A= new char[100]; 
    recv(receive_then_send_A_Socket_b, buffer_A, 100, 0); 
    printf("[2]What I first receive: %s\n",buffer_A); 

    //- Check receiver Port 
    struct sockaddr_storage receiver_addr; 
    socklen_t receiver_addr_len = (socklen_t)sizeof receiver_addr; 
    getpeername(receive_then_send_A_Socket_b, (struct sockaddr*)&receiver_addr, &receiver_addr_len); 


    struct sockaddr_in *s = (struct sockaddr_in *)&receiver_addr; 
    inet_ntop(AF_INET, &s->sin_addr, share_addr, sizeof share_addr); 
    receiver_port = ntohs(s->sin_port); 
    printf("[2]The port I want to send to:%ld\n",receiver_port); 
    close(receive_then_send_A_Socket); 
    close(receive_then_send_A_Socket_b); 

    //- Send Back to the port that sender send to me 
    struct sockaddr_in receive_then_send_B_Addr; 
    receive_then_send_B_Addr.sin_family = AF_INET; 
    inet_pton(AF_INET, share_addr, &receive_then_send_B_Addr.sin_addr.s_addr); 
    receive_then_send_B_Addr.sin_port = htons((u_short)receiver_port); 
    receive_then_send_B_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 
    while (connect(receive_then_send_B_Socket, (struct sockaddr *)&receive_then_send_B_Addr, sizeof(sockaddr_in)) == SOCKET_ERROR){ 
     printf("\nFail Code:%i\n", WSAGetLastError()); 
     break; 
    } 
    send(receive_then_send_B_Socket, "1234", 5, 0); 
    close(receive_then_send_B_Socket); 
    printf("[2]The port I want to send to:%ld\n",receiver_port); 
} 

int main(int argc, char *argv[]) 
{ 
    ThreadB = std::thread(receive_then_send); 
    ThreadA = std::thread(send_then_receive); 
    while(1); 
    return 0; 
} 

然而,它運作良好,在第一次傳輸,但它不工作在第二次傳輸,什麼是錯的?

它這樣表示:

連接失敗的第一反應|失敗代碼:111

Connect in Fail in first response |失敗碼:111 [1]我想 的端口發送至:8000 [1] MyPort上檢查:34004 [2]我第一次收到4321 [2]我要發送到的端口:34004

失敗代碼:111

請注意:我使用Linux(第二次傳輸不起作用),但是當我修改爲WinSock版本時,所有功能都很好。爲什麼會發生?

請注意,在綁定之前,我已經厭倦了 //將套接字上的SO_REUSEADDR設置爲true(1): int optval = 1; setsockopt(receive_then_send_A_Socket,SOL_SOCKET,SO_REUSEADDR,& optval,sizeof(int));

回答

1

One liner answer:SO_REUSEADDR

系統禁止重複使用給定端口上的IP地址,我記得它在釋放後60秒。除非SO_REUSEADDR標誌已被設置。

這是一個comprehensive answer on SO關於爲什麼以及如何設置此選項標誌。

+0

我累了,但問題仍然存在(SO_REUSEADDR) –

+0

直言,你的代碼真的沒有多大意義。當另一方連接時,您無法確保一方正在傾聽。 –