The system I have to do has one tcp server and about 1000 tcp clients.
1000 clients will send data to tcp server every second.
To simulate this situation, At first I connected to tcp server with 50 sockets from a single pc with below code.
int main() {
const char *hello = "Hello from client";
struct sockaddr_in serv_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(8080);
serv_addr.sin_addr.s_addr = inet_addr("192.168.1.39");
vector<int> vec;
for ( uint8_t i = 0; i < 50; i++ ) {
int sock = socket(AF_INET, SOCK_STREAM, 0);
if ( sock < 0 ) {
cout << "... Cant Allocated Socket\n";
return -1;
}
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
cout << "... Connection Failed \n";
return -1;
}
vec.push_back(sock);
}
for ( uint8_t i = 0; i < vec.size(); i++ ) {
send(vec[i], hello, strlen(hello), 0);
cout << "Message Send\n";
}
for ( uint8_t i = 0; i < vec.size(); i++ ) {
shutdown(vec[i], 0);
close(vec[i]);
}
return 0;
}
After the tcp clients connect to the tcp server, they send the data to the tcp server and close the socket. I can see from terminal that tcp clients can send packet without waiting(less than 10ms)
The above tcp client code can work successfully and send the data to tcp server successfully.
I show the data from the tcp client with the tcp server code below.
#define _DEF_TCP_SERVER_PORT 8080
#define _DEF_TCP_SERVER_MAX_QUEUE_LISTEN 12
bool finish_app = false;
struct TcpClient {
int clientSocket;
struct in_addr clientAddr;
};
vector<TcpClient> TcpClients;
struct _ServiceTcpServer {
bool enable;
int sock;
uint16_t connectedClient;
uint32_t sockLen;
sockaddr_in tcpServerAddr;
sockaddr_in remoteAddr;
};
struct _ServiceTcpServer _serviceTcpServer;
void init_tcp_server_socket() {
_serviceTcpServer.tcpServerAddr.sin_addr.s_addr = htonl(INADDR_ANY);
_serviceTcpServer.tcpServerAddr.sin_family = AF_INET;
_serviceTcpServer.tcpServerAddr.sin_port = htons(_DEF_TCP_SERVER_PORT);
_serviceTcpServer.sockLen = sizeof(_serviceTcpServer.remoteAddr);
int flag = 1;
for ( ;; ) {
_serviceTcpServer.sock = socket(AF_INET, SOCK_STREAM, 0);
if ( _serviceTcpServer.sock < 0 ) {
cout << "... Failed to allocate socket.\n";
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if ( setsockopt(_serviceTcpServer.sock, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)) ) {
cout << "... Set SockOpt failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if( bind(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.tcpServerAddr, sizeof(_serviceTcpServer.tcpServerAddr)) == -1 ) {
cout << "... Socket bind failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
if ( listen(_serviceTcpServer.sock, _DEF_TCP_SERVER_MAX_QUEUE_LISTEN) != 0 ) {
cout << "... Socket listen failed.\n";
close(_serviceTcpServer.sock);
this_thread::sleep_for(chrono::seconds(1));
continue;
}
break;
}
cout << "Socket init done \n";
}
void tcp_user_accept_task() {
while ( finish_app == false ) {
int temp_sck = -1;
temp_sck = accept(_serviceTcpServer.sock, (sockaddr *) &_serviceTcpServer.remoteAddr, &_serviceTcpServer.sockLen);
if ( temp_sck == -1 ) {
this_thread::sleep_for(chrono::seconds(2));
continue;
}
TcpClient tcpClient;
tcpClient.clientAddr = _serviceTcpServer.remoteAddr.sin_addr;
tcpClient.clientSocket = temp_sck;
TcpClients.push_back( tcpClient );
cout << "... New connection request: " << temp_sck << endl;
++_serviceTcpServer.connectedClient;
this_thread::sleep_for(chrono::milliseconds(50));
}
}
uint8_t temp_recv[100];
void tcp_server_run() {
while ( finish_app == false ) {
for(uint16_t i = 0 ; i < _serviceTcpServer.connectedClient; i++ ) {
int temp_cs = TcpClients[i].clientSocket;
fcntl(temp_cs, F_SETFL, O_NONBLOCK);
int temp_recvLen = recv(temp_cs, temp_recv, 20, 0);
if( temp_recvLen > 0 ) {
time_t _time = chrono::system_clock::to_time_t(chrono::system_clock::now());
cout << "Message Received At:" << ctime(&_time) << " :";
cout << temp_recv << endl;
break;
} else {
this_thread::sleep_for(chrono::milliseconds(10));
}
}
if ( temp_recv[0] == 'q' ) {
finish_app = true;
}
}
close(_serviceTcpServer.sock);
}
int main() {
thread init_thread(init_tcp_server_socket);
init_thread.join();
thread accept_thread(tcp_user_accept_task);
thread run_thread(tcp_server_run);
accept_thread.join();
run_thread.join();
return 0;
}
But the problem is about 3-4 packets received in only 1 second as in the screen image.
Note:
When the code this_thread::sleep_for(chrono::milliseconds(10)); commented, the problem was solved. But since the processor is not sleep, the processor is working at 100%.
When the client is accepted, I added 10 us timeout to client recv with the code below and comment and fcntl(temp_cs, F_SETFL, O_NONBLOCK);
struct timeval _timeval;
_timeval.tv_sec = 0;
_timeval.tv_usec = 10;
setsockopt(tcpClient.clientSocket, SOL_SOCKET, SO_RCVTIMEO, (const char*) &_timeval, sizeof(_timeval));
The problem continues as in "this_thread::sleep_for".
You should receive the socket simultaneously rather than querying every socket and sleeping for 10ms each time data is not yet ready.
The proper way to do it depends on the platform
posix - select
linux - poll, epoll, io_submit
windows - I/O Completion Ports
Usually, select which is a posix standard, will be sufficient for your needs.
If you want multiplatform you might also want to explorer 3rd party libraries such as libevent and libev which already wraps theses platform depent calls for you.
Happy Coding!
Related
I want to create two projects with this code so that they can chat with each other, but no matter how much I send, the data does not reach the other client.
I've been thinking and trying for hours on this problem, but it doesn't work. Various multicast chat programs on the web are written in languages other than C++, some use threads and some do not. To the best of my knowledge right now, I can't understand the codes on the web.
For fear of lengthy code, the basic header file and error output function have been omitted.
// header file and function declaration
#define MAXBUF 80
SOCKADDR_IN maddr;
int main(int argc, char* argv[]) {
int port;
cout << "input port number" << endl;
cin >> port;
cout << "use port : " << port << endl;
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa))
{
err_display("WSAStartup");
return -1;
}
//create send socket
SOCKET r_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (r_sock == INVALID_SOCKET)
{
err_display(" recv socket");
return -1;
}
//create recv socket
SOCKET s_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s_sock == INVALID_SOCKET)
{
err_display(" send socket");
return -1;
}
// bind
maddr.sin_family = AF_INET;
maddr.sin_port = htons(port);
maddr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(r_sock, (SOCKADDR*)&maddr, sizeof(maddr))) {
err_display("bind");
return -1;
}
// Join the Multicast address
const char* mip = "236.0.0.1";
IP_MREQ mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY); // s_addr = 주소
// Setting Multicast address
if (!(inet_pton(AF_INET, mip, &mreq.imr_multiaddr))) {
err_display("inet_pton");
return -1;
}
// JOIN
if (setsockopt(r_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq))) {
err_display("setsockopt");
return -1;
}
while (true) {
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, &sendf, (LPVOID)s_sock, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, &recvf, (LPVOID)r_sock, 0, NULL);
}
closesocket(r_sock);
closesocket(s_sock);
WSACleanup();
return 0;
}
unsigned __stdcall sendf(LPVOID arg) // send thread function
{
SOCKET s_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int sendlen;
while (1)
{
// send
char mesbuf[MAXBUF];
if (fgets(mesbuf, MAXBUF - 1, stdin) == NULL)
break;
cout << "send Thread" << endl;
sendlen = strlen(mesbuf);
sendto(s_sock, mesbuf, sendlen, 0, (SOCKADDR*)&maddr, sizeof(maddr));
}
return 0;
}
unsigned __stdcall recvf(LPVOID arg) // recv thread function
{
SOCKADDR_IN paddr; // peer address
int namelen = sizeof(paddr);
SOCKET r_sock = (SOCKET)arg;
char mesbuf[MAXBUF];
int recvlen;
while (1)
{
char mesbuf[MAXBUF];
//recive
recvlen = recvfrom(r_sock, mesbuf, MAXBUF - 1, 0, (SOCKADDR*)&paddr, &namelen);
cout << "recv Thread" << endl;
if (recvlen == SOCKET_ERROR) {
err_display("recv error");
closesocket(r_sock);
break;
}
if (recvlen == 0)
{
cout << "normal close connection case" << endl;
closesocket(r_sock);
break;
}
mesbuf[recvlen] = '\0'; // string conversion
cout << "from : " << mesbuf << endl;
}
return 0;
}
I have written code in C++ with Winsock. It converts a video to mjpeg stream and sends it over TCP using Winsock in windows. Now I am able to see the video in any browser with the link.
But the problem is that anyone with the link can see it. I want to prompt the user to enter username and password to access the feed, whenever he types the IP address.
Here is my code:
#include <winsock.h>
#include <windows.h>
#include <time.h>
#define PORT unsigned long
#define ADDRPOINTER int*
struct _INIT_W32DATA
{
WSADATA w;
_INIT_W32DATA() { WSAStartup( MAKEWORD( 2, 1 ), &w ); }
} _init_once;
#include <iostream>
using std::cerr;
using std::endl;
#include <iostream>
#pragma comment(lib, "wsock32.lib")
using namespace std;
class MJPGWriter
{
SOCKET sock;
fd_set master;
int timeout; // master sock timeout, shutdown after timeout millis.
int quality; // jpeg compression [1..100]
int _write( int sock, char *s, int len )
{
if ( len < 1 ) { len = strlen(s); }
return ::send( sock, s, len, 0 );
}
public:
MJPGWriter(int port = 0)
: sock(INVALID_SOCKET)
, timeout(20000)
, quality(30)
{
FD_ZERO( &master );
if (port)
open(port);
}
~MJPGWriter()
{
release();
}
bool release()
{
if ( sock != INVALID_SOCKET )
::shutdown( sock, 2 );
sock = (INVALID_SOCKET);
return false;
}
bool open( int port )
{
sock = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP) ;
SOCKADDR_IN address;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_family = AF_INET;
address.sin_port = ::htons(port);
if ( ::bind( sock, (SOCKADDR*) &address, sizeof(SOCKADDR_IN) ) == SOCKET_ERROR )
{
cerr << "error : couldn't bind sock "<<sock<<" to port "<<port<<"!" << endl;
return release();
}
if ( ::listen( sock, 10 ) == SOCKET_ERROR )
{
cerr << "error : couldn't listen on sock "<<sock<<" on port "<<port<<" !" << endl;
return release();
}
FD_SET( sock, &master );
return true;
}
bool isOpened()
{
return sock != INVALID_SOCKET;
}
bool write(const cv::Mat & frame)
{
fd_set rread = master;
struct timeval to = {0,timeout};
SOCKET maxfd = sock+1;
if ( ::select( maxfd, &rread, NULL, NULL, &to ) <= 0 )
return true; // nothing broken, there's just noone listening
std::vector<uchar>outbuf;
std::vector<int> params;
params.push_back(cv::IMWRITE_JPEG_QUALITY);
params.push_back(quality);
cv::imencode(".jpg", frame, outbuf, params);
int outlen = outbuf.size();
#ifdef _WIN32
for ( unsigned i=0; i<rread.fd_count; i++ )
{
SOCKET s = rread.fd_array[i]; // fd_set on win is an array, while ...
#else
for ( int s=0; s<maxfd; s++ )
{
if ( ! FD_ISSET(s,&rread) ) // ... on linux it's a bitmask ;)
continue;
#endif
if ( s == sock ) // request on master socket, accept and send main header.
{
int addrlen = sizeof(SOCKADDR);
SOCKADDR_IN address = {0};
SOCKET client = ::accept( sock, (SOCKADDR*)&address, &addrlen );
if ( client == SOCKET_ERROR )
{
cerr << "error : couldn't accept connection on sock " << sock<< " !" << endl;
return false;
}
maxfd=(maxfd>client?maxfd:client);
FD_SET( client, &master );
_write( client,"HTTP/1.0 200 OK\r\n",0);
_write( client,
"Server: Mozarella/2.2\r\n"
"Accept-Range: bytes\r\n"
"Connection: close\r\n"
"Max-Age: 0\r\n"
"Expires: 0\r\n"
"Cache-Control: no-cache, private\r\n"
"Pragma: no-cache\r\n"
"Content-Type: multipart/x-mixed-replace; boundary=mjpegstream\r\n"
"\r\n",0);
cerr << "new client " << client << endl;
}
else // existing client, just stream pix
{
char head[400];
sprintf(head,"--mjpegstream\r\nContent-Type: image/jpeg\r\nContent-Length: %lu\r\n\r\n",outlen);
_write(s,head,0);
int n = _write(s,(char*)(&outbuf[0]),outlen);
//cerr << "known client " << s << " " << n << endl;
if ( n < outlen )
{
cerr << "kill client " << s << endl;
::shutdown(s,2);
FD_CLR(s,&master);
}
}
}
return true;
}
};
I am using it by sending image frame and port number to writer.
I'm working on a multithreaded UDP listener and I'm stuck in a problem that definitely surpasses me.
So, I'm required to receive huge amounts of UDP packets in several ports. Locally, the best solution for me was to call non blocking recvfrom in as much threads as ports I'm listening (select and poll were too slow for my requirements). I'm using a thread pool manager, it simply calls on threads and queues tasks. Here's the code:
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_DONTWAIT, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
//cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
struct arg_struct args;
args.arg_port = port;
memcpy(args.buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(&args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
struct arg_struct_listenPort args;
args.arg_fd = *i;
args.arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(&args));
}
cout << "Listening threads created..." << endl;
return 0;
}
This works perfectly fine locally. But when I compile it on a production environment, some ports listen the packets and other's simply don't! And the working ports change in each execution. I can , confirm that it is not a firewall problem. I also can clearly see the packets through Wireshark. I can receive packets on those ports through netcat. Netstat shows all ports open.
My local environment is an Ubuntu 18.04 VM, and the production environment is a Debian 9.8.
Here's how I call the sockets:
int lSocket(int port) {
//Crear Socket
int listening = socket(AF_INET, SOCK_DGRAM, 0);
if (listening == -1) {
cerr << "No se puede crear el socket";
exit(EXIT_FAILURE);
}
//Enlazar socket a un IP / puerto
struct sockaddr_in hint;
memset(&hint, 0, sizeof(hint));
hint.sin_family = AF_INET; //IPv4
hint.sin_port = htons(port); //Port
hint.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(listening, (struct sockaddr*)&hint, sizeof(hint)) == -1) { //Enlaza las opciones definidas al socket
cerr << "No se puede enlazar IP/puerto" << endl;
exit(EXIT_FAILURE);
}
return listening;
}
Any advise is greatly appreciated!
EDIT:
As suggested, I tried switching to blocking I/O, but the main issue remains. Still not receiving at all the opened ports.
What an amazing welcome!
#molbdnilo was absolutely right:
You're using pointers to objects whose lifetime has ended (&args).
This has undefined behaviour - it might appear to work, but it's a bug
that needs a-fixin'.
Here's the fixed code. Gotta be careful when feeding arguments to threads!
void receiveFromSocket(void * arguments){
sockaddr_in client; // Local
socklen_t clientSize = sizeof(client);
memset(&client, 0, sizeof(client));
struct arg_struct_listenPort *args2 = (struct arg_struct_listenPort *)arguments;
int fd = args2->arg_fd;
int port = args2->arg_port;
for(;;) {
char buf[158];
memset(buf,0,158*sizeof(char));
int n = recvfrom(fd, (char * ) buf, 158, MSG_WAITALL, ( struct sockaddr *) &client, &clientSize);
if(n == -1){
cerr << "Error while receiving from client: " << errno << endl;
continue;
}
if(n != 158){
cerr << "Discarded message since it's not 158 bytes." << endl;
continue;
}
arg_struct *args = new arg_struct;
args->arg_port = port;
memcpy(args->buf,buf,158);
thpool_add_work(globals.thpool, socketThread, (void*)(args));
}
}
/// Runs the Socket listener
int network_accept_any()
{
vector<int>::iterator i;
for(i = globals.fds.begin(); i != globals.fds.end(); i++){
int port = distance(globals.fds.begin(),i);
arg_struct_listenPort *args = new arg_struct_listenPort;
args->arg_fd = *i;
args->arg_port = globals.cmnSystemCatalogs[port].diag_port;
thpool_add_work(globals.thpool, receiveFromSocket, (void*)(args));
}
cout << "Listening threads created..." << endl;
return 0;
}
Also, I'll keep an eye on #John Bollinger 's and #Superlokkus comments.
Thank you all!
1) I am trying to make a simple game server using UDP. Would my code be the correct way to check if there is any reads from a single socket?
2) I want to recieve data from one user on a request ( he wants to move left), then update where the server thinks he or she is located, then broadcast the x , y coordinates. How would I implement a multicast reply with a different socket?
void run()
{
//logging file
ofstream log;
log.open("server_log.txt", ios::out | ios::app);
struct sockaddr_in myaddr; // our address
struct sockaddr_in remaddr; // remote address
socklen_t addrlen = sizeof(remaddr);
int recvlen;
int fd; // server socket that listens
int fd_reply; // this will be used to reply to all users
char buf[BUFSIZE]; // receive buffer
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: cannot create socket! " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) {
std::time_t result = std::time(nullptr);
log << "Error: bind failed " << "TIMESTAMP: " << std::asctime(std::localtime(&result)) << endl;
log.close();
return 0;
}
pollfd fds;
memset(fds, 0, sizeof(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
while (1)
{
int rv = poll(ufds, 1, 3500);
if (rv == -1)
{
// error occured
}
else if (rv == 0)
{
//time out
}
else
{
//check for events on fd
if (fds.revents & POLLIN)
{
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
}
}
}
}
Yes it looks okay.
Keep a list of all clients, and then in a loop send to all of them. To populate this list, all clients need to contact the server the first thing they do.
I want to make a server and client program with TCP protocol using C++. The server must be able to handle multiple client at once. But the problem is for example, after starting the server, I run 2 clients with the server 's IP address and port as parameters. Next, both clients are sending data to server. At first, both clients could send data to server and the server was able read the data. But, once the server has received data from the second client, it seems that it stopped receiving from the first client. Do you have any solution?
Here is the server code
using namespace std;
void *task1(void *);
static int connFd;
void error(const char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char* argv[])
{
int pId, portNo, listenFd;
socklen_t len; //store size of the address
bool loop = false;
struct sockaddr_in svrAdd, clntAdd;
pthread_t threadA[3];
if (argc < 2)
{
cerr << "Syntam : ./server <port>" << endl;
return 0;
}
portNo = atoi(argv[1]);
if((portNo > 65535) || (portNo < 2000))
{
cerr << "Please enter a port number between 2000 - 65535" << endl;
return 0;
}
//create socket
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
bzero((char*) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
svrAdd.sin_addr.s_addr = INADDR_ANY;
svrAdd.sin_port = htons(portNo);
//bind socket
if(bind(listenFd, (struct sockaddr *)&svrAdd, sizeof(svrAdd)) < 0)
{
cerr << "Cannot bind" << endl;
return 0;
}
listen(listenFd, 5);
int noThread = 0;
while (noThread < 3)
{
socklen_t len = sizeof(clntAdd);
cout << "Listening" << endl;
//this is where client connects. svr will hang in this mode until client conn
connFd = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
if (connFd < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
cout << "Connection successful" << endl;
}
pthread_create(&threadA[noThread], NULL, task1, NULL);
noThread++;
}
for(int i = 0; i < 3; i++)
{
pthread_join(threadA[i], NULL);
}
}
void *task1 (void *dummyPt)
{
cout << "Thread No: " << pthread_self() << endl;
char test[256];
bzero(test, 256);
bool loop = false;
while(!loop)
{
bzero(test, 256);
int n = read(connFd, test, 255);
if (n < 0) error("ERROR reading from socket");
printf("Here is the message: %s\n",test);
}
cout << "\nClosing thread and conn" << endl;
close(connFd);
}
And the client code
using namespace std;
int main (int argc, char* argv[])
{
int listenFd, portNo;
bool loop = false;
struct sockaddr_in svrAdd;
struct hostent *server;
if(argc < 3)
{
cerr<<"Syntax : ./client <host name> <port>"<<endl;
return 0;
}
portNo = atoi(argv[2]);
if((portNo > 65535) || (portNo < 2000))
{
cerr<<"Please enter port number between 2000 - 65535"<<endl;
return 0;
}
//create client skt
listenFd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenFd < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}
server = gethostbyname(argv[1]);
if(server == NULL)
{
cerr << "Host does not exist" << endl;
return 0;
}
bzero((char *) &svrAdd, sizeof(svrAdd));
svrAdd.sin_family = AF_INET;
bcopy((char *) server -> h_addr, (char *) &svrAdd.sin_addr.s_addr, server -> h_length);
svrAdd.sin_port = htons(portNo);
int checker = connect(listenFd,(struct sockaddr *) &svrAdd, sizeof(svrAdd));
if (checker < 0)
{
cerr << "Cannot connect!" << endl;
return 0;
}
//send stuff to server
for(;;)
{
char s[300];
//cin.clear();
//cin.ignore(256, '\n');
cout << "Enter stuff: ";
bzero(s, 300);
cin.getline(s, 300);
write(listenFd, s, strlen(s));
}
}
Yor connFd is a global variable, which you access from your main thread and all handling threads. This will not do! Imagine that - you've accepted the first connection and set the variable to the receiving socket. You've spawn the handling thread, which started reading. Next thing you know, another connection is coming along and you are receiving it as well! This very moment connFd points to the new connection, so the thread which is already using it will suddenly switch to the new connection! Of course it is not good.
The way to fix this problem is to pass the connection to the thread in such a way that is is not shared across threads. And easiest way of doing so is to use C++ thread class.
For example, this is code fragment illustrating the above idea:
void handle_connection(int fd) {
... <your task1 code>
}
...
std::vector<std::thread> threads;
...
int conn = accept(listenFd, (struct sockaddr *)&clntAdd, &len);
threads.push_back(std::thread(&handle_connection, conn));
...
... (in the end)
for (auto&& t : threads)
t.join();