我目前正在用 C 语言编写一个用于学习网络的小型聊天应用程序。 我使用传输控制协议(protocol)和 C 中的套接字进行开发。我能够使用不是我自己编码的客户端(在本地网络上)连接到我的服务器。现在,telnet 成功连接到我的聊天服务器(因此服务器和 telnet 客户端位于同一台计算机上),我可以发送和接收消息,但我非常简单的客户端无法连接到它。 从一开始我就使用端口 9002,现在我尝试使用 IPv6 地址::1 进行连接。 这是我的服务器的“接受客户端”代码:
int main(void)
{
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
printf("Socket créer\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = in6addr_any;
//Bind the socket on the port
if(bind(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr_in6)) == SO_ERROR)
{
perror("bind()");
errx(EXIT_FAILURE, "Fail to bind");
}
//Make the sockey listen the port
if(listen(sock, MAX_CLIENT) == SO_ERROR)
{
perror("listen()");
errx(EXIT_FAILURE, "Fail to listen");
}
printf("Socket listening\n");
int csock;
size_t clientID = 0;
--snip--
while(1)
{
struct sockaddr_in6 csin6;
memset(&csin6, 0, sizeof(struct sockaddr_in6));
int sin6size = sizeof(struct sockaddr_in6);
//Accept a communication
printf("Wait for communication\n");
csock = accept(sock, (struct sockaddr *) &csin6, &sin6size);
printf("Connection accepted\n");
char msg[16];
sprintf(msg, "CONNECTED - %zu\n", clientID);
send(csock, msg, sizeof(msg), 0);
printf("Client %zu connected\n", clientID);
//Handle client
--snip--
}
这是使用连接通信与套接字的基本连接。由于线程化,服务器在 while 循环中处理多个客户端。
这是客户端的代码:
void *sender(void *arg)
{
int socket = (int)(long)arg;
char buffer[BUFF_SIZE];
while(1)
{
scanf("%s", buffer);
send(socket, buffer, strlen(buffer), 0);
bzero(buffer, BUFF_SIZE);
}
}
int main(int argc, char *argv[])
{
if(argc < 2)
errx(EXIT_FAILURE, "Usage: ./client <server ip>\n");
//Create the socket
int sock = socket(AF_INET6, SOCK_STREAM, 0);
struct hostent *hostinfo = NULL;
hostinfo = gethostbyname2(argv[1], AF_INET6);
if(hostinfo == NULL)
errx(EXIT_FAILURE, "Can't connect to the server\n");
//Set up the socket interface
struct sockaddr_in6 sin6 = { 0 };
sin6.sin6_family = AF_INET6;
sin6.sin6_port = htons(PORT);
sin6.sin6_addr = *(struct in6_addr *)hostinfo->h_addr;
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
{
perror("connect()");
errx(EXIT_FAILURE, "Fail to connect");
}
printf("Connection established\n");
pthread_t sending;
if(pthread_create(&sending, NULL, sender, (void *)(long)sock) != 0)
printf("Fail to create a thread\n");
//Handle reception
char buffer[BUFF_SIZE];
int n;
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
{
buffer[n] = '\0';
printf("%s", buffer);
}
printf("Erreur: %d\nConnection broken\n", n);
pthread_cancel(sending);
close(sock);
return EXIT_SUCCESS;
}
所以我启动客户端:
~ ./client ::1
输出如下:
Connection established
Error: -1
Connection broken
当服务器仍处于“等待通信”状态时。这意味着服务器不接受连接,但客户端连接成功。
感谢您的帮助。
最佳答案
它可能已经是 connect()
,这里失败了:
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == SO_ERROR)
SO_ERROR
并不打算在此处使用,而是作为异步连接失败时检索错误时的套接字选项。 (同步)connect()
出错时返回 -1 并设置 errno
,所以这样做
if(connect(sock, (struct sockaddr *) &sin6, sizeof(struct sockaddr)) == -1) {
...
稍后,这里的recv:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
失败并显示 errno ENOTCONN
,因为连接事先失败。
相同的SO_ERROR
错误出现在服务器代码的不同位置;有可能,bind()
已经失败了!然后,对 listen()
的调用会将其自动绑定(bind)到空闲的临时端口,因此该调用以及对 accept()
的调用都会成功。
为什么调用bind()
会失败? (重新)启动服务器时,您可能必须设置套接字选项 SO_REUSEADDR
,否则如果连接仍处于 TIME_WAIT
状态,服务器可能会拒绝使用最近绑定(bind)的端口。将其直接放在 bind()
调用之前:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
这可能会有所帮助。
关于可以通过 telnet 访问我的服务器,但不能通过我的客户端访问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54443442/