我正在尝试学习c语言中的低级网络,并且已经学会了使用winsock制作、绑定、连接、接受等套接字的TCP客户端和服务器程序。
它们工作得很好,当两个程序在同一台计算机上运行时,我的简单聊天控制台可以按预期工作,但通过我的本地网络或另一个网络从另一台电脑上的客户端连接时,无法通过套接字连接进行通信。
这是我的服务器:
#include "sockets.h"
int main(){
// SETUP AND BIND SERVER SOCKET
SOCKET server_socket = socket_setup();
SOCKADDR_IN address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("192.168.xx.xxx"); //using public IP, not local (127.0.0.1)
address.sin_port = htons(6502);
if(bind(server_socket, (SOCKADDR*)&address, sizeof(address)) == SOCKET_ERROR)
WSA_ERR("Socket Bind Error");
if(listen(server_socket, 5) == SOCKET_ERROR)
WSA_ERR("Listening Error");
SOCKET accept_socket = SOCKET_ERROR;
do{
accept_socket = accept(server_socket, NULL, NULL);
}
while(accept_socket == SOCKET_ERROR);
// SEND AND RECEIVE BYTES
char sendmsg[100] = "Hello Client";
char recvmsg[100] = "";
int bytes_sent = send(accept_socket, sendmsg, strlen(sendmsg), 0);
if(bytes_sent == SOCKET_ERROR){
WSA_ERR("Send Error");
}else{
printf("Send OK\n");
printf("Bytes Sent: %ld\n", bytes_sent);
printf("%s\n", sendmsg);
}
int bytes_rcvd = blocking_recv(accept_socket, recvmsg);
if(bytes_rcvd == SOCKET_ERROR){
WSA_ERR("Recv Error");
}else{
printf("Recv OK\n");
printf("Bytes Rcvd: %ld\n", bytes_rcvd);
printf("%s\n", recvmsg);
}
chat_loop(recvmsg, sendmsg, accept_socket);
return 0;
}
和客户:
#include "sockets.h"
int main(){
// SETUP AND CONNECT CLIENT SOCKET
SOCKET client_socket = socket_setup();
SOCKADDR_IN address;
address.sin_family = AF_INET;
printf("Enter IP address:\n");
char ip[15];
gets_s(ip, 15);
address.sin_addr.s_addr = inet_addr(ip);
address.sin_port = htons(6502);
if(connect(client_socket, (SOCKADDR*)&address, sizeof(address)) == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK){
WSA_ERR("Connection Error");
}
// SEND AND RECIEVE BYTES
char sendmsg[100] = "Hello Server";
char recvmsg[100] = "";
int bytes_rcvd = blocking_recv(client_socket, recvmsg);
if(bytes_rcvd == SOCKET_ERROR){
WSA_ERR("Recv Error"); //<-- WSAGetLastError() from inside macro gives error 10057 here
}else{
printf("Recv OK\n");
printf("Bytes Rcvd: %ld\n", bytes_rcvd);
printf("%s\n", recvmsg);
}
int bytes_sent = send(client_socket, sendmsg, strlen(sendmsg), 0);
if(bytes_sent == SOCKET_ERROR){
WSA_ERR("Send Error");
}else{
printf("Send OK\n");
printf("Bytes Sent: %ld\n", bytes_sent);
printf("%s\n", sendmsg);
}
chat_loop(recvmsg, sendmsg, client_socket);
system("pause");
return 0;
}
此函数是“sockets.h”的一部分:
int blocking_recv(SOCKET sock, char buf[]){
int result = 0;
do{
result = recv(sock, buf, 100, 0);
}while(result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK);
return result;
}
如果需要,我可以详细说明排除的代码和宏,但我认为问题一定出在此处,因为除了实际连接之外,一切都工作正常。
我已经禁用了所有防火墙、转发端口等。 我正在使用非阻塞套接字。
服务器需要
bind()
属于运行服务器的计算机的本地 IP。否则,您可以将服务器 bind()
改为 INADDR_ANY
(0.0.0.0
) 来绑定到计算机上的所有本地 IP。
客户端可以
connect()
连接到服务器绑定并侦听的任何IP:
如果客户端和服务器运行在同一台机器上,则可以使用任何本地IP,或者
INADDR_LOOPBACK
(127.0.0.1
)。
如果客户端和服务器在同一 LAN 网络上运行,则
bind
服务器到机器的 LAN IP 或 INADDR_ANY
,然后 connect()
客户端到服务器的 LAN IP。
如果客户端和服务器运行在不同的网络上,则客户端需要
connect()
到属于服务器网络的公共WAN IP,并且服务器网络上的路由器必须配置为启用端口转发才能通过从 WAN 到运行服务器的 LAN 计算机的传入连接。根据路由器的配置,其端口转发规则可以可以通过 uPNP 协议直接从服务器代码动态配置,否则规则必须由网络管理员手动配置。