Cpp套接字 - TCP传输(发送然后用同一端口接收)

时间:2015-11-05 13:10:54

标签: c++ linux sockets tcp

我正在编写一个socket编程,一部分是先发送然后接收,一部分是接收然后发送。

程序的工作方式如下:

  

ThreadA:发送到端口8000->关闭套接字 - >得到我发送的myport(portA) - >听我的端口(portA)

     

ThreadB:侦听端口8000 - >收到时获取端口(portA) - >关闭套接字 - >将包发送到同一端口(端口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

     

在第一个响应中连接失败|失败代码: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 个答案:

答案 0 :(得分:1)

单线答案:SO_REUSEADDR

系统禁止在给定端口上重用IP地址,我记得,它已经被释放60秒。除非已设置SO_REUSEADDR标志。

以下是关于为何以及如何设置此选项标记的comprehensive answer on SO