I have a program that serves both as client and as server without multi-threading (as far as I know accept should let the program continue up until a certain connection is occurs).
The thing is, that my friend has a very similar program (not multithreaded) that also serves as both client AND server and it totally works, I'm trying to accomplish the same thing and accept() stops the program.
The code is as the following:
//main.cpp
#include <iostream>
#include "Client.h"
#include "Server.h"
#pragma comment(lib, "Ws2_32.lib")
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
Server s(6666);
Client c("127.0.0.1", 6666);
cout << "Done";
WSACleanup();
return 0;
}
Server.cpp (two variables, SOCKET _socket and struct sockaddr_in _details):
Server::Server(unsigned short Port) : _socket(0)
{
this->_socket = socket(AF_INET, SOCK_STREAM, 0);
if (_socket < 0)
throw "Invalid socket";
ZeroMemory(&this->_details, sizeof(this->_details));
this->_details.sin_family = AF_INET;
this->_details.sin_port = htons(Port);
this->_details.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (bind(this->_socket, (const struct sockaddr*)&this->_details, sizeof(this->_details)) != 0)
{
throw "Bind Unsuccessful";
}
this->AcceptConnections();
}
void Server::AcceptConnections()
{
if (listen(this->_socket, SOMAXCONN) != 0)
throw "Listen Unsuccessful";
void* buf = NULL;
string ans("Accepted");
int client;
struct sockaddr_in client_addr;
int addrlen = sizeof(client_addr);
client = accept(this->_socket, (struct sockaddr*)&client_addr, &addrlen);
/*THIS IS WHERE THE PROGRAM STOPS... AWAITING CONNECTIONS*/
//NEVER REACHING THE CODE HERE
int recvBytes = this->Receive(buf, MY_MAX_LEN);
if (recvBytes <= 0)
{
throw "Client disconnected";
}
this->Send((void*)ans.c_str(), ans.length());
closesocket(client);
closesocket(this->_socket);
}
And client.cpp is irrelevant as it doesn't even encounter its code.
Why does this happen? How come my friend has a code with no multi-threading that has both client and server. By the way, Send and Receive are functions implemented by me.
Related
I'm attempting to teach myself some networking programming in C++, but I'm running into some core issues that I can't seem to solve.
I have two programs that are in the same VS project- a client and a server. They don't exchange information, they simply connect and tell me when the connection is established. Here is the client file-
SERVER.CPP
#include "stdafx.h"
using namespace std;
int main()
{
//setting up WSA
WSADATA wsaData;
int WSAcheck = WSAStartup(MAKEWORD(2, 2), &wsaData);
//checking WSA
if (WSAcheck != 0)
{
printf("WSA couldn't start correctly\n");
pause();
exit;
}
//setting up the socket
SOCKET serversock = socket(AF_INET, SOCK_STREAM, 0);
//checking socket's validity
if (serversock == INVALID_SOCKET)
{
printf("Socket isn't valid: %d\n", WSAGetLastError());
pause();
exit;
}
//setting up the sockaddr_in for bind()
sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
server_sockaddr.sin_port = htons(25565);
//binding the socket.
int bindcheck = bind(serversock, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr));
//checking to see if the bind worked, and calling the error if it doesn't
if (bindcheck != 0)
{
printf("Bind failed: %d\n", WSAGetLastError());
pause();
exit;
}
//setting the socket to listen
int listencheck = listen(serversock, 10);
//checking to make sure the listen command was successful
if (listencheck != 0)
{
printf("Listen failed: %d\n", WSAGetLastError());
pause();
exit;
}
//telling that the socket is being set to listen
printf("Socket is ready to accept connections\n");
//accepting any incoming connections
SOCKET clientsocket = accept(serversock, NULL, NULL);
//checking the socket
if (clientsocket == INVALID_SOCKET)
{
printf("Connecting socket isn't valid or has timed out: %d\n", WSAGetLastError());
pause();
exit;
}
//ending the program
printf("fin\n");
pause();
}
CLIENT.CPP
#include "stdafx.h"
using namespace std;
int main()
{
//setting up WSA
WSADATA wsaData;
int WSAcheck = WSAStartup(MAKEWORD(2, 2), &wsaData);
//checking WSA
if (WSAcheck != 0)
{
printf("WSA couldn't start correctly\n");
pause();
exit;
}
//setting up the socket
SOCKET clientsock = socket(AF_INET, SOCK_STREAM, 0);
//checking socket's validity
if (clientsock == INVALID_SOCKET)
{
printf("Socket isn't valid: %d\n", WSAGetLastError());
pause();
exit;
}
//setting up the struct with the connection info
sockaddr_in serverinfo;
serverinfo.sin_family = AF_INET;
serverinfo.sin_addr.s_addr = INADDR_ANY;
serverinfo.sin_port = htons(25565);
//connecting
printf("Trying to connect\n");
connect(clientsock, (SOCKADDR *)&serverinfo, sizeof(serverinfo));
printf("Passed the connect function\n");
pause();
}
STDAFX.H
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <Inaddr.h>
#include <string.h>
#include <io.h>
#include <Windef.h>
#include <Ws2tcpip.h>
#include <WinNT.h>
#include <Windows.h>
#include <tchar.h>
void pause(void); //defined in stdafx.cpp
pause is defined as getchar(), to break the code to see what is going on.
The output for the client is -
Trying to connect
Passed the connect function
regardless of whether the server process is running.
The output for the server is
The socket is ready to accept connections
regardless of what I test, I cannot get it to pass that.
What am I doing wrong?
You have an error in the client. This is bad:
serverinfo.sin_addr.s_addr = INADDR_ANY;
Instead of INADDR_ANY you have to write the server IP address, maybe 127.0.0.1 if they run in the same server, in binary format.
Use this function to convert from text IP address to binary IP address:
INT WSAAPI InetPton(
_In_ INT Family,
_In_ PCTSTR pszAddrString,
_Out_ PVOID pAddrBuf
);
https://msdn.microsoft.com/en-us/library/windows/desktop/cc805844(v=vs.85).aspx
The code would be:
if(InetPton(AF_INET, "192.168.0.1", (void*)&serverinfo.sin_addr.s_addr) <= 0)
{
//error
}
I'm creating a game in C++ for a university project which requires some feature of networking using Sockets. My module lecturer gave us example code of working (local machine) client/servers to show us how it works. He has the following code for setting up the socket, which works fine:
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
#define SERVERIP "127.0.0.1"
#define SERVERPORT 5555
void main(){
WSADATA w;
int error = WSAStartup(0x0202, &w);
if (error != 0)
{
die("WSAStartup failed");
}
if (w.wVersion != 0x0202)
{
die("Wrong WinSock version");
}
// Create a TCP socket that we'll use to listen for connections.
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == INVALID_SOCKET)
{
die("socket failed");
}
// Fill out a sockaddr_in structure to describe the address we'll listen on.
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(SERVERIP);
// htons converts the port number to network byte order (big-endian).
serverAddr.sin_port = htons(SERVERPORT);
// Bind the server socket to that address.
if (bind(serverSocket, (const sockaddr *) &serverAddr, sizeof(serverAddr)) != 0)
{
die("bind failed");
}
}
However, when I replicate most of the code, bind(...) function keeps returning -1, as opposed to the 0 in my lecturers example. Here is the relevant part of my code, using classes:
TCPSocket.h
#define SERVERIP "127.0.0.1"
#define SERVERPORT 5555
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
class TCPSocket {
public:
TCPSocket();
~TCPSocket();
void SetupServer(char* serverIP_, int serverPort_, int messageSize_);
protected:
private:
SOCKET m_socket;
sockaddr_in m_serverAddress;
char* m_serverIP;
int m_serverPort;
int m_messageSize;
};
TCPSocket.cpp
TCPSocket::TCPSocket() {
// Initialise WinSock Library, version 2.2
WSADATA w;
int error = WSAStartup(0x0202, &w);
if(error != 0) {
//error
int i = 0;
}
if(w.wVersion != 0x0202) {
//error
int i = 0;
}
}
void TCPSocket::SetupServer(char* serverIP_, int serverPort_, int messageSize_) {
m_serverIP = serverIP_;
m_serverPort = serverPort_;
m_messageSize = messageSize_;
// Create TCP socket
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if(m_socket == INVALID_SOCKET) {
//error
int i = 0;
}
m_serverAddress.sin_family = AF_INET;
m_serverAddress.sin_addr.s_addr = inet_addr(SERVERIP);
m_serverAddress.sin_port = htons(SERVERPORT); // htons: port -> network byte order (big-endian)
// Bind server socket to address
int bindex = bind(m_socket, (const sockaddr *) &m_serverAddress, sizeof(m_serverAddress));
if(bindex != 0) {
//error
int a = 0;
}
}
As I said in a comment, I made a silly mistake outwith the scope of the included code: basically I was running the SetupServer() function within an update loop and the error was being caught on the second iteration of the update. Besides that, the code is perfectly functional.
I have UDP Server program which receives data from port 7888. The server code is below.
//UDPIPV4Server.h
#pragma once
#include <iostream>
#include <string>
#include <winsock2.h>
#include <windows.h>
#include <Ws2tcpip.h>
using std::string;
using std::cout;
using std::endl;
using std::cerr;
class UDPIPV4Server
{
public:
UDPIPV4Server();
~UDPIPV4Server(void);
UINT type;
string mac_address;
UINT port;
int socket_var;
struct sockaddr_in si_server, si_client;
int Config(void);
int RecvData(char* recv_buffer, int buf_size,string *ip_addr);
};
//UDPIPV4Server.cpp
int UDPIPV4Server::Config(void) {
WSADATA wsadata;
int error = WSAStartup(0X0202, &wsadata);
if(error) {
cerr<<"UdpIPV4Server.cpp:- WSAStartup failed"<<endl;
return -1;
}
if ((socket_var = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
cerr<<"UdpIPV4Server.cpp:- socket function failed"<<endl;
return -1;
}
memset((char *) &si_server, 0, sizeof(si_server));
si_server.sin_family = AF_INET;
si_server.sin_port = htons(7888);
char host[NI_MAXHOST] = "10.8.0.2";
if(inet_pton(AF_INET, host, &si_server.sin_addr) != 1) {
cerr<<"UdpIPV4Server.cpp: inet_pton() failed\n";
return -1;
}
if(bind(socket_var,(struct sockaddr *)&si_server,sizeof(si_server)) == -1) {
cerr<<"UdpIPV4Server.cpp:- bind failed: "<<endl;
return -1;
}
return 0;
}
//recv data from the UDP client
//recv_buffer - [out] receive buffer
//buf_size - [in] size of receive buffer in bytes
//ip_addr - [out] ip address of the remote client
int UDPIPV4Server::RecvData(char* recv_buffer, int buf_size, string *ip_addr) {
int recv_len;
cout<<"waiting for data\n";
memset((char*)&si_client, 0, sizeof(struct sockaddr_in));
int si_client_len = sizeof(si_client);
if((recv_len = recvfrom(socket_var, recv_buffer, buf_size, 0, (struct sockaddr *)&si_client, &si_client_len)) == -1) {
cerr<<"udpipv4server.cpp:- recvfrom failed"<<endl;
return recv_len;
}
char client_addr[INET_ADDRSTRLEN];
cout<<"Received packets from "<<inet_ntoa(si_client.sin_addr)<<":"<<ntohs(si_client.sin_port)<<endl;
*ip_addr = inet_ntoa(si_client.sin_addr);
return recv_len;
}
//main.cpp
#include "UDPIPV4Server.h"
int main() {
UDPIPV4Server udp_server;
udp_server.Config();
char recv_frame_buffer[65534] = "";
memset(recv_frame_buffer,0,sizeof(recv_frame_buffer));
int retval;
string ip_addr;
if((retval = udp_server.RecvData(recv_frame_buffer,sizeof(recv_frame_buffer),&ip_addr)) == -1) {
cerr<<"ReceiverCommModule:- Error in receving data"<<endl;
continue;
}
}
The above program receives data on 10.8.0.2:7888. But this code is not working when data is received. I have checked with wireshark, the data is being received at 10.8.0.2:7888. But socket is unable to read the data from the port.The UDPIPV4Server.config() function passed successfully. But the UDPIPV4Server.RecvData() is not returning. The UDP recvfrom is waiting as such there is no data received. Is it anything wrong with the code? Thank you.
I had the same issue. in UDP, recvfrom behaves as if no data were available dispite wireshark confirmed that a valid UDP packet arrived on the correct port. It happens on my compagny's computer but it works fine on my personnal one. I guess this is linked to windows fire wall or antivir that filters incoming packets if the associated port is not allowed for your software. I noticed that recvfrom works once, just after having sent packet through the same port. May be this is linked to my computer's config.
I have a very simple recvfrom() command that works fine - so long as it is not called in "another" thread.
I would post more code, but there is quite a bit of it, so hopefully I can filter out the relevant bits:
First we have the global variable: SOCKET Socket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);.
So long as threads are not involved, this works fine:
char message[_max_message_];
struct sockaddr_in* from;
int r;
int SenderAddrSize = sizeof (struct sockaddr);
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n",r,WSAGetLastError);
Now I have identical code called behind a thread, like this:
pthread_create(&listener, NULL, listenloop, &Socket);
(The code basically ignores &socket.)
The first recvfrom() to execute, from the called thread, returns -1, but the recvfrom() from the "original" thread (where the networking was setup) successfully fills message with the, well, message from the server.
So kind as to tell me what I'm doing wrong?
EDIT: I hate to throw more than a dozen lines at strangers kind enough to help me, but I don't think I'm gonna get an answer if I don't. So, here is the kit and kaboodle, edited slightly:
#include <iostream>
//#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <conio.h>
using namespace std;
#include <string>
//One thread shall listen continually for responses from the server.
/*The other thread shall listen continually for user input, and fire off user input at the local
client to the server...*/
//#ifdef _WINDOWS
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
inline int randport()
{
return (50000 % rand() + 1000);
}
#define _serverip_ "***.***.***.***"
#define _welcome_ "Welcome,Wagon!"
#define _randomport_ 64000%rand()+100
#define _max_message_ 100
void *listenloop(void *arg)
{
//SOCKET* listener = (SOCKET)arg;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
int r;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
//while (1){
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Thread Bytes recieved: %i\nThread Error Code: %i\n", r,
WSAGetLastError);
return NULL ;
//}
return NULL ;
}
int main()
{
string user, pass, login;
WSADATA WsaDat;
WSAStartup(MAKEWORD(2, 0), &WsaDat);
int port;
cout << "Welcome!"
SOCKET Socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
fflush(stdin); //As long as we compile with GCC Behavoir should be consistant
//TRY NOT TO SEND PLAINTEXT PASSWORDS LIKE THIS! IT MAY MAKE YOUR USERS VULNERABLE! DONE FOR SAKE OF SIMPLICITY HERE!
cout << "\n\nPlease enter the username you registered with:";
getline(cin, user);
cout << "\nPlease enter your password, my good sir: ";
getline(cin, pass);
struct hostent *host;
host = gethostbyaddr(_serverip_, strlen(_serverip_), AF_INET);
if (host == NULL )
{
cout << "\n\n UNABLE TO CONNECT TO SERVER. QUITTING. ";
return -1;
}
short errorcount = 3;
int socketfeedback;
///Put the address for the server on the "evelope"
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = inet_addr(_serverip_);
///Sign the letter...
int myport = _randomport_;
int code;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_addr.s_addr = inet_addr("localhost");
service.sin_port = htons(myport);
//bind(Socket, (SOCKADDR *) &service, sizeof(service));
//Start a thread, listening for that server
while ((errorcount))
{
code = bind(Socket, (SOCKADDR *) &service, sizeof(service));
if (code)
break;
else
return -5;
errorcount--;
myport = _randomport_;
service.sin_port = htons(myport);
}
login = user + ',' + pass;
if (!errorcount)
{
cout << "\n\nMiserable failure. Last Known Error Code: " << code;
return -1;
}
///Begin the listen loop!!
pthread_t listener;
pthread_create(&listener, NULL, listenloop, &Socket);
struct sockaddr result;
sendto(Socket, login.c_str(), strlen(login.c_str()), 0,
(struct sockaddr *) &SockAddr, sizeof(SockAddr));
char message[_max_message_];
//SOCKET listener=(SOCKET)arg;
//sockaddr_in SenderAddr;
struct sockaddr_in from;
int r;
int SenderAddrSize = sizeof(struct sockaddr);
r = recvfrom(Socket, message, _max_message_, 0, (struct sockaddr *) &from,
&SenderAddrSize);
printf("Bytes recieved: %i\nError Code: %i\n", r, WSAGetLastError);
//SOCKET listener=(SOCKET)arg;
WSACleanup();
return 0;
}
Why do you use global Socket? And why are you declaring another Socket in main? You should better use the socket passed in pthread_create (just cast args in listenloop to SOCKET *). Global variables in multithreaded are a really bad idea (you need synchronization mechanism). And initialize your struct sockaddr_in from with zeros (for e.g. with memset, or just do as alk said : struct sockaddr_in from = {0}).
And also you are reading from one socket in two different threads without any kind of synchronization. This is bound to cause many errors.
And also I see a problem with WSACleanup and recvfrom in other thread. You don't know in what order will these two run (so you can also get WSACleanup before you can recvfrom in other thread).You can use pthread_join to wait for other thread to finish and then do WSACleanup.
This is too long for a comment.
The code as posted would not work at all, due to declaring:
struct sockaddr_in* from;
and then using from like this:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)&from,&SenderAddrSize);
You are paasing the address of the address of struct sockaddr_in instead of only its address.
Is shall be:
r=recvfrom(Socket,message,_max_message_,0,(struct sockaddr *)from,&SenderAddrSize);
However if doing so you are missing to allocate memory to from.
So propably
struct sockaddr_in* from;
is a typo and should have read:
struct sockaddr_in from = {0};
?
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();
}
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.
void* input(void* ptr)
{
int on = 1;
bool *input_done = ((struct thread_args*)ptr)->process_done;
int ret;
int success = true;
struct sockaddr_in addrLocal = {};
struct addrinfo *res = ((struct thread_args*)ptr)->result;
char msg[256];
int sock = socket(AF_INET, SOCK_STREAM, 0);
success = (sock != -1);
if (success)
{
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = INADDR_ANY; // INADDR_ANY == 0 --> pick a random port for me
addrLocal.sin_addr.s_addr = INADDR_ANY; // INADDR_ANY == 0 --> use all appropriate network
ret = bind(sock,(sockaddr*)&addrLocal,sizeof(addrLocal));
if (ret == -1) perror("bind: ");
success = (ret != -1);
}
if (success)
{
ret = connect(sock,res->ai_addr,res->ai_addrlen);
if (ret == -1) perror("connect: ");
success = (ret != -1);
}
if (success)
{
cin.getline(msg,256);
if (msg[0] == '/') {exit(1);}
ret = send(sock,msg,sizeof msg,0);
if (ret == -1) perror("send: ");
success = (ret != -1);
}
if (success)
{
cout << "You:" << msg << endl;
*input_done = 1;
}
if (sock != -1)
{
close(sock);
sock = -1;
}
return NULL;
}
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.