我正在写一个套接字程序,一部分是先发送然后接收,一部分是接收然后发送。
程序是这样运行的:
ThreadA: Send to Port 8000-> close socket -> get myport (portA) that i send -> listen to my port(portA)
ThreadB: Listen port 8000 -> Get the port when receive (portA)-> close socket -> send pack to same port (port 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;
}
但是,第一次传输很好用,第二次传输就不行了,怎么回事???
显示如下:
Connect Fail in first response| Fail Code:111
Connect Fail in first response| Fail Code:111 [1]The port I want to send to:8000 [1]MyPort Check:34004 [2]What I first receive: 4321 [2]The port I want to send to:34004
Fail Code:111
注意:我用的是Linux(二次传输不行),但是修改成WinSock版本后一切正常。为什么会这样?
请注意,在绑定(bind)之前,我已经厌倦了 //将套接字上的 SO_REUSEADDR 设置为真 (1): int optval = 1; setsockopt(receive_then_send_A_Socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
最佳答案
一个类轮答案:SO_REUSEADDR
.
系统禁止在给定端口上重复使用 IP 地址,我记得,在它被释放后 60 秒内。除非设置了 SO_REUSEADDR
标志。
这是一个comprehensive answer on SO关于为什么以及如何设置这个选项标志。
关于c++ - cpp socket - TCP 传输(使用相同的端口发送和接收),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33545467/