我目前正在用C编写一个用于学习网络的小型聊天应用程序。 我使用带有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
虽然服务器仍在“等待通信”。这意味着服务器不接受连接,但是客户端成功连接。
感谢您的帮助。
答案 0 :(得分:1)
可能已经是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) {
...
稍后,这里的收录:
while((n = recv(sock, buffer, BUFF_SIZE - 1, 0)) >= 0)
由于连接失败而导致错误errno ENOTCONN
失败。
同一SO_ERROR
错误出现在服务器代码的各个位置;那里的bind()
可能已经失败了!然后,对listen()
的呼叫将自动将其绑定到一个免费的以弗弗勒尔端口,因此该呼叫以及对accept()
的呼叫将成功。
为什么对bind()
的呼叫失败? (重新)启动服务器时,可能必须设置套接字选项SO_REUSEADDR
,否则,如果连接仍处于TIME_WAIT
状态,则它可能拒绝使用最近绑定的端口。将其直接放在bind()
调用之前:
int one = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
这可能有帮助。