地址已被使用。
最近,我一直在编写一些客户端代码,用于使用线程从服务器发送和接收消息。下面的代码在运行时表现得很奇怪。输入要发送到服务器的消息后,代码完成任务,尽管出现“套接字已在使用”错误,但服务器会获取它。但是我尝试发送到服务器的每条后续消息都不会立即收到,但似乎在客户端程序终止时立即全部收到。
(此外,我确定错误是客户端的,如果对输出函数进行注释,则不会表现出奇怪的行为。)
如何修复此错误?
客户端
#include <stdio.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>
#include <errno.h>
#include <pthread.h>
void* input(void* ptr)
{
int on = 1;
bool *input_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
cin.getline(msg,256);
if (msg[0] == '/') {exit(1);}
send(sock,msg,sizeof msg,0);
cout << "You:" << msg << endl;
*input_done = 1;
close(sock);
pthread_exit(NULL);
}
void* output(void* ptr)
{
int on = 1;
bool *output_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
recv(sock,msg,sizeof msg,0);
cout << "Recieved:" << msg;
*output_done = 1;
close(sock);
pthread_exit(NULL);
}
void io_client()
{
//thread function variables
pthread_t t1,t2;
bool input_done = 1, output_done = 1;
//socket setup variables
struct addrinfo hints, *res;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
//setting up structures to pass data to threaded functions
struct thread_args i_args, o_args;
i_args.result = res; i_args.process_done = &input_done;
o_args.result = res; o_args.process_done = &output_done;
while(1)
{
if (output_done)
{
pthread_create(&t2,NULL,output,&o_args);
output_done = 0;
}
if (input_done)
{
pthread_create(&t1,NULL,input,&i_args);
input_done = 0;
}
}
}
int main()
{
io_client();
}
服务器
void server()
{
struct addrinfo hints, *res;
int sock=-1, newsock=-1;
int length, on=1;
char **address_list; int entries = 0;
//fd_set read_fd;
//struct timeval timeout;
char buffer[100];
memset(&hints,0,sizeof hints);
res = NULL;
memset(&res,0,sizeof res);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
listen(sock,10);
while(1)
{
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
socklen_t len;
len = sizeof addr;
newsock = accept(sock,NULL,NULL);
getpeername(newsock,(struct sockaddr*)&addr,&len);
struct sockaddr_in *s = (struct sockaddr_in*)&addr;
inet_ntop(AF_INET,&s->sin_addr,ipstr,sizeof ipstr);
length = 100;
setsockopt(newsock,SOL_SOCKET,SO_RCVLOWAT, (char*)&length,sizeof length);
recv(newsock,buffer,sizeof buffer,0);
cout << buffer << endl;
}
if (newsock != -1)
{
close(newsock);
}
if (sock != -1)
{
close(sock);
}
}
int main()
{
server();
}
Recently I have been working on some client-side code for sending and receiving messages from a server using threading. The below code behaves strangely when run. Upon inputting a message to send to the server, the code completes the task, albeit with a "socket already in use" error, the server gets it. But every subsequent message I attempt to send to the server is not received immediately, yet it is seemingly all received at once when the client program terminates.
(Additionally, I am certain the error is client-side, the strange behavior isn't exhibited if one comments the output function.)
How can I fix this error?
Client
#include <stdio.h>
#include <cstdlib>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string>
#include <iostream>
#include <errno.h>
#include <pthread.h>
void* input(void* ptr)
{
int on = 1;
bool *input_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
cin.getline(msg,256);
if (msg[0] == '/') {exit(1);}
send(sock,msg,sizeof msg,0);
cout << "You:" << msg << endl;
*input_done = 1;
close(sock);
pthread_exit(NULL);
}
void* output(void* ptr)
{
int on = 1;
bool *output_done = ((struct thread_args*)ptr)->process_done;
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
bind(sock,res->ai_addr,res->ai_addrlen);
connect(sock,res->ai_addr,res->ai_addrlen);
recv(sock,msg,sizeof msg,0);
cout << "Recieved:" << msg;
*output_done = 1;
close(sock);
pthread_exit(NULL);
}
void io_client()
{
//thread function variables
pthread_t t1,t2;
bool input_done = 1, output_done = 1;
//socket setup variables
struct addrinfo hints, *res;
memset(&hints,0,sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
//setting up structures to pass data to threaded functions
struct thread_args i_args, o_args;
i_args.result = res; i_args.process_done = &input_done;
o_args.result = res; o_args.process_done = &output_done;
while(1)
{
if (output_done)
{
pthread_create(&t2,NULL,output,&o_args);
output_done = 0;
}
if (input_done)
{
pthread_create(&t1,NULL,input,&i_args);
input_done = 0;
}
}
}
int main()
{
io_client();
}
Server
void server()
{
struct addrinfo hints, *res;
int sock=-1, newsock=-1;
int length, on=1;
char **address_list; int entries = 0;
//fd_set read_fd;
//struct timeval timeout;
char buffer[100];
memset(&hints,0,sizeof hints);
res = NULL;
memset(&res,0,sizeof res);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("localhost","8080",&hints,&res);
sock = socket(res->ai_family,res->ai_socktype,res->ai_protocol);
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on));
bind(sock,res->ai_addr,res->ai_addrlen);
listen(sock,10);
while(1)
{
struct sockaddr_storage addr;
char ipstr[INET6_ADDRSTRLEN];
socklen_t len;
len = sizeof addr;
newsock = accept(sock,NULL,NULL);
getpeername(newsock,(struct sockaddr*)&addr,&len);
struct sockaddr_in *s = (struct sockaddr_in*)&addr;
inet_ntop(AF_INET,&s->sin_addr,ipstr,sizeof ipstr);
length = 100;
setsockopt(newsock,SOL_SOCKET,SO_RCVLOWAT, (char*)&length,sizeof length);
recv(newsock,buffer,sizeof buffer,0);
cout << buffer << endl;
}
if (newsock != -1)
{
close(newsock);
}
if (sock != -1)
{
close(sock);
}
}
int main()
{
server();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
看起来您正在尝试将客户端绑定()到与服务器相同的端口。那没有必要。更糟糕的是,您试图绑定到服务器的 IP 地址 - 这也是一个更大的问题。一般来说,对于要调用 connect() 函数的客户端套接字,您应该将套接字绑定到端口 0 和 IP 0,从而让操作系统为您选择一个随机可用的端口,并允许使用正确的本地 IP 地址和用于连接的适配器。您可以在调用 connect 后调用 getsockname() 来发现操作系统为您选择的端口。
如果您让操作系统为您选择客户端端口,您将不需要 SO_REUSESADDR 调用。尽管如此,您的服务器代码可以在关闭后需要重新启动且连接仍待关闭的情况下调用它。
还。您没有检查任何套接字调用的返回值。这可能就是为什么您会得到一些神秘结果的原因。对 bind() 的调用更有可能失败,因为您指定了服务器 IP,但 connect() 成功了,因为它会自动绑定套接字(如果尚未绑定)。
这是 input() 函数的清理版本。转换你的output()函数是留给读者的练习。如果你效仿我的榜样,你就会保持良好的状态。
It looks like you are trying to have your client bind() to the same port as the server. That's not necessary. And worse, you are trying to bind to to the IP address of the server - which is also a bigger problem. In general, for client sockets that are to call the connect() function, you should just have your socket bind to port 0 and IP 0, thus letting the OS pick a randomly available port for you and enabling use the right local IP address and adapter for the connection. You can call getsockname() to discover what port the OS picked for you after you call connect.
And if you let the OS pick the client port for you, you won't need that SO_REUSESADDR call. Although, your server code could call it for cases where it needs to restart after shutting down with connections still pending to close.
Also. you aren't checking the return value of any of your socket calls. That's probably why you are getting some mysterious results. The call to bind() is more likely failing because you are specifying the server IP, but connect() is succeeding because it will auto-bind the socket if it hasn't already.
Here's a cleaned up version of you input() function. Converting your output() function is an exercise left up to the reader. If you follow my example, you'll be in good shape.
我想您提供的“SO_REUSEADDR”套接字选项就是问题所在。
您是否一次又一次地调用该函数而不关闭客户端套接字?在这种情况下,它将不起作用。
此套接字选项的目的是“当同一地址已打开的套接字处于 TIME_WAIT 状态时重用该地址,否则您将收到上述错误”。
如果您的客户端每次都打开一个新连接,那么我必须说您必须更有效地构建代码并处理套接字关闭场景。
I guess that "SO_REUSEADDR" socket option that you are giving is the problem.
Are you calling that function again and again without closing the client socket ? In that case it will not work.
The purpose of this socket option is to "reuse the address when the already opened socket for the same address is in TIME_WAIT state else you will get the mentioned error".
If you client is opening a new connection each and every time, then I must say that you will have to structure your code more efficiently and handle the socket closing scenarios as well.