I'm a newbie in multithread, so the problem is: I'm trying to make multiple threads send message to a server, ever thread represents a device. The server who I'm testing has 10k ports open so every socket has his exclusively port. The problem is the program subtly stops and don't send all messages from all devices. I'm using a vector of futures to simulate the devices, that way:
vector<future<void>> futures;
map<string,vector<string> >::iterator it = mapDevtoMessage.begin();
for(it = mapDevtoMessage.begin(); it != mapDevtoMessage.end(); it++){
futures.push_back(async(launch::async,[&]{ send_messages(it->second, it->first);}));
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
for(auto &its : futures){
its.wait();
}
The code for send_messages is:
void send_messages (vector<string>& vec, string name){
mtx.lock();
PORT++;
mtx.unlock();
int sock = 0, client_fd;
struct sockaddr_in serv_addr;
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("\n Socket creation error \n");
}
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
printf("\nInvalid address/ Address not supported \n");
}
if ((client_fd
= connect(sock, (struct sockaddr*)&serv_addr,
sizeof(serv_addr)))
< 0) {
printf("\nConnection Failed \n");
}
for(auto &i : vec){
string val = hexToASCII(i);
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
send(sock, val.c_str(), 100, 0);
mtx.lock();
printf("\nmessage %s from %s send\n", i.c_str() , name.c_str());
mtx.unlock();
}
// closing the connected socket
close(client_fd);
}
I added the for loop with the wait() method because the program keep terminating unexpectledly without any error or anything. So I added, but the program continues to subtle terminate. I tried an endless loop also. I may have missed a simple thing (I'm a noob), please let me know.
Related
This is my first time coding something using WinSock2 and I tried making a simple chat program which should detect if the server disconnected and then should try to reconnect until a successful connection has been made. (Also: the client connects to server via a No-IP DNS) This is the code:
main.cpp:
void keepAliveSEND(const char* IP, int port) {
TCPClient ack(IP, port);
ack.connecttcp();
while (true) {
ack.synchronizeSEND();
ack.synchronizeGET();
}
}
void keepAliveGET(TCPClient* client, const char* IP, int port) {
TCPClient ack(IP, port);
ack.connecttcp();
unsigned long nonblock = 1;
ioctlsocket(ack.ssocket, FIONBIO, &nonblock);
while (true) {
auto t1 = std::chrono::high_resolution_clock::now();
bool loop = true;
bool timeout = true;
while (loop) {
char recvbuff[1024];
int ByteReceived = 0;
ByteReceived = recv(ack.ssocket, recvbuff, sizeof(recvbuff), 0);
if (ByteReceived > 0) {
std::string str = "";
for (int i = 0; i < ByteReceived; i++) {
str += recvbuff[i];
}
timeout = false;
}
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1);
long ldur = duration.count();
if (ldur >= 2000) {
loop = false;
if (timeout) {
client->reconnect();
ack.reconnect();
}
}
}
ack.synchronizeSEND();
}
}
int main() {
using namespace std;
TCPClient client(DNS, 4444);
client.connecttcp();
thread t(keepAliveGET, &client, DNS, 4443);
thread t2(keepAliveSEND, DNS, 4442);
while (true) {
//Chat-Code only active upon succesful connection and startchat-command from user
}
return 0;
}
TCPClient.cpp:
void TCPClient::connecttcp() {
WSAStartup(MAKEWORD(2, 2), &wsaData);
ADDRINFO hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
ADDRINFO *res;
getaddrinfo(HostIP, NULL, &hints, &res);
char ipbuf[INET_ADDRSTRLEN];
InetNtop(AF_INET, &((SOCKADDR_IN*)res->ai_addr)->sin_addr, ipbuf, sizeof(ipbuf));
this->IP = ipbuf;
ssocket = WSASocketW(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, NULL, NULL);
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(port);
InetPton(AF_INET, (PCSTR)IP, &ServerAddr.sin_addr.s_addr);
while (connect(ssocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) {
Sleep(1000);
}
}
void TCPClient::reconnect() {
closesocket(ssocket); //EDIT1: Added this line, doesn't change anything
while (connect(ssocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR) {
Sleep(1000);
}
}
void TCPClient::synchronizeSEND() {
sendData("ACK");
}
void TCPClient::synchronizeGET() {
while (true) {
std::string Ack = receiveData(3);
if (Ack == "ACK") {
return;
}
}
}
void TCPClient::closeConnection() {
closesocket(ssocket);
WSACleanup();
}
When the server closes and then starts again it will listen on port 4444,4443&4442 for ingoing connections and this is why I want to call connect() to reconnect.
When connecttcp() is called for the first time (upon execution) only 0.9MB RAM are being used up by this process. But as soon as the server disconnects and thus reconnect() is called the RAM starts rising quite a bit reaching almost 1.5GB in about 15 seconds which is not acceptable behaviour. I tried to debug the code in Visual Studio an it seems that connect(ssocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr)) is causing the memory to go up. But it's still able to reconnect...
I already tried to call closesocket(ssocket) before reconnecting but that didn't help either...
I read somewhere that Winsock waits up to 4min before it frees the connect() resources. Could that be why it behaves like that?
How can I solve this sort of thing?
I am coding in C++ using winsock api. I am making a multi- client server chat. The problem that I am encountering in my code is that my server is able to send the message to the client only once. But I want this to happen multiple times. I cannot put accept() function out of infinite loop in server code. I have used select() for multi client. I am doing it without threading.
Server:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
// See who's talking to us
int socketCount = select(0, ©, nullptr, nullptr, nullptr);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
//Send a new message
string mssg;
getline(cin, mssg);
int bytes = send(sock, mssg.c_str(), mssg.size() + 1, 0);
for (int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening && outsock != sock) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
}
Client code:
#include<iostream>
#include<ws2tcpip.h>
#include<string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
void main() {
string ipAddress = "127.0.0.1"; //IP Address of the server
int port = 54000; //Listening port on the sever
//Initialize Winsock
WSADATA data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0) {
cerr << " Can't initialize winsock " << endl;
return;
}
//Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
cerr << "Can't create a socket " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Fill in a hint structure
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
inet_pton(AF_INET, ipAddress.c_str(), &hint.sin_addr);
//Connect to the server
int connResult = connect(sock, (sockaddr*)&hint, sizeof(hint));
if (connResult == SOCKET_ERROR) {
cerr << " Can't connect to the server " << WSAGetLastError() << endl;
closesocket(sock);
WSACleanup();
return;
}
//Do-While loop to send and receive data
//char b[4096];
//int bytes = recv(sock,b,4096, 0);
//cout << string(b, 0, bytes) << endl;
char buff[4096];
string userInput;
do {
//Prompt the user
//cout << ">";
//getline(cin, userInput);
//Send the result
//int sendResult = send(sock, userInput.c_str(), userInput.size() + 1, 0);
//if (sendResult != SOCKET_ERROR) {
//ZeroMemory(buff, 0);
int bytesrecieved = recv(sock, buff, 4096, 0);
if (bytesrecieved > 0) {
//Echo response to console
cout << "SERVER> " << string(buff, 0, bytesrecieved) << endl;
}
//}
} while (true);
//Shut down everything
closesocket(sock);
WSACleanup();
}
EDIT:
You should do some modifications :
Use timeval for select to avoid the blocking select (wait until a
new connection was made or there is something to read).
Move the read/send message section out of the for loop.
Separate key input processing in an other thread.
Use a safe queue to share the input between the input thread and the communciation one(main thread).
Here is an example:
#include <iostream>
#include <WS2tcpip.h>
#include <string>
#include <sstream>
#include <thread>
#include <mutex>
#include <list>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
class safe_queue {
mutex m;
list<string> str_queue;
public:
safe_queue() {};
void add(const string &s) {
const lock_guard<mutex> lock(m);
str_queue.push_back(s);
}
bool pop( string &s ) {
const lock_guard<mutex> lock(m);
if (!str_queue.empty()) {
s = str_queue.front();
str_queue.pop_front();
return true;
}
return false;
}
};
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
cerr << "Can't Initialize winsock! Quitting" << endl;
return 0;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton ....
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell Winsock the socket is for listening
listen(listening, SOMAXCONN);
// Create the master file descriptor set and zero it
fd_set master;
FD_ZERO(&master);
// Add our first socket that we're interested in interacting with; the listening socket!
// It's important that this socket is added for our server or else we won't 'hear' incoming
// connections
FD_SET(listening, &master);
// this will be changed by the \quit command (see below, bonus not in video!)
bool running = true;
safe_queue sq;
auto io_thread = thread([&] {
string s;
while (running && getline(std::cin, s, '\n')){
sq.add(s);
}
});//thread.
while (running)
{
// Make a copy of the master file descriptor set, this is SUPER important because
// the call to select() is _DESTRUCTIVE_. The copy only contains the sockets that
// are accepting inbound connection requests OR messages.
// E.g. You have a server and it's master file descriptor set contains 5 items;
// the listening socket and four clients. When you pass this set into select(),
// only the sockets that are interacting with the server are returned. Let's say
// only one client is sending a message at that time. The contents of 'copy' will
// be one socket. You will have LOST all the other sockets.
// SO MAKE A COPY OF THE MASTER LIST TO PASS INTO select() !!!
fd_set copy = master;
timeval tv = {0,0};
// See who's talking to us
int socketCount = select(0, ©, nullptr, nullptr, &tv);
for (int i = 0; i < socketCount; i++) {
//Accept a new connection
SOCKET sock = copy.fd_array[i];
if (sock == listening) {
//Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
//Add a new connection
FD_SET(client, &master);
string mssg = "Welcome to the awesome chat server\n";
//Send a welcome message to the connected client
send(client, mssg.c_str(), mssg.size() + 1, 0);
}
}//for.
string mssg;
if (sq.pop(mssg) ) {
std::cout << "Send :" << mssg << endl;
for (u_int i = 0; i < master.fd_count; i++) {
SOCKET outsock = master.fd_array[i];
if (outsock != listening) {
send(outsock, mssg.c_str(), mssg.size() + 1, 0);
}
}
}
}//while
// Remove the listening socket from the master file descriptor set and close it
// to prevent anyone else trying to connect.
FD_CLR(listening, &master);
closesocket(listening);
// Message to let users know what's happening.
string msg = "Server is shutting down. Goodbye\r\n";
while (master.fd_count > 0)
{
// Get the socket number
SOCKET sock = master.fd_array[0];
// Send the goodbye message
send(sock, msg.c_str(), msg.size() + 1, 0);
// Remove it from the master file list and close the socket
FD_CLR(sock, &master);
closesocket(sock);
}
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
So I'm writing a very basic TCP server which just echoes back the messages sent from the client back to the client. I have a setup where the server is running in a while loop and waiting for either a new client to connect or for a message from one of the existing clients using the select() method.
My question is:
How do i, from the server side, close the master socket and basically shutting down the server. Im not asking for exact code but more for standard practice.
For some context:
In the long run I am imagining multiple clients connected to my server and I need to shutdown the server gracefully from the server side.
Even more context: The server code.
#define TRUE 1
#define FALSE 0
#define PORT 55555
int main(int argc, char* argv[])
{
int opt = TRUE;
int masterSocket, addrlen, newSocket, maxClients = 10, clientSockets[maxClients],
activity, valread, sd, maxSd;
struct sockaddr_in address;
char buffer[1025];
fd_set readfds;
const char *message = "ECHO DAMON v1.0 \r\n";
/* Initialize array with 0 so it's not read */
for(int i = 0; i < maxClients ; i++)
{
clientSockets[i] = 0;
}
/* Create master socket */
if((masterSocket = socket(AF_INET, SOCK_STREAM,0)) == 0)
{
perror("Error when trying to create master socket.\n");
exit(EXIT_FAILURE);
}
/* Set master socket to allow multiple connections */
if( setsockopt(masterSocket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0)
{
perror("Could not set sockopt");
exit(EXIT_FAILURE);
}
/* Socket type */
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
if( bind(masterSocket, (struct sockaddr*)&address, sizeof(address)) < 0)
{
perror("Error, could not bind master socket. \n");
exit(EXIT_FAILURE);
}
printf("Listening on %d. \n", PORT);
if( listen(masterSocket, 3) < 0)
{
perror("Error, could not listen.\n");
exit(EXIT_FAILURE);
}
addrlen = sizeof(address);
puts("Waiting for connections...\n"); //just a printf variant
/* END INIT */
while(TRUE)
{
/* Clear socket set */
FD_ZERO(&readfds);
/* Add master socket to set */
FD_SET(masterSocket, &readfds);
/* Add child sockets to set, will be 0 first iteration */
for(int i = 0; i < maxClients ; i++)
{
sd = clientSockets[i]; // sd = socket descriptor
/* If valid socket descriptor */
if(sd > 0)
{
FD_SET(sd, &readfds);
}
/* Get highest fd number, needed for the select function (later) */
if(sd > maxSd)
{
maxSd = sd;
}
}//end for-loop
/* Wait for activity on any socket */
activity = select(maxSd +1, &readfds, NULL, NULL, NULL);
if((activity < 0) && (errno != EINTR))
{
printf("Error on select.\n"); //no need for exit.
}
/* If the bit for the file descriptor fd is set in the
file descriptor set pointed to by fdset */
/* If something happend in the master socket, its a new connection */
if(FD_ISSET(masterSocket, &readfds))
{
if((newSocket = accept(masterSocket, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0)
{
perror("Could not accept new socket.\n");
exit(EXIT_FAILURE);
}
/* Print info about connector */
printf("New connection, socket fd is %d, ip is: %s, port: %d\n", newSocket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
if( send(newSocket, message, strlen(message), 0) != strlen(message))
{
perror("Could not sent welcome message to new socket.\n");
}
puts("Welcome message sen successfully.\n");
/* Add new socket to array of clients */
for(int i = 0; i < maxClients; i++)
{
if(clientSockets[i] == 0)
{
clientSockets[i] = newSocket;
printf("Adding socket to list of client at index %d\n", i);
break;
}
}
}//end masterSocket if
/* Else something happend at client side */
for(int i = 0; i < maxClients; i++)
{
sd = clientSockets[i];
if(FD_ISSET(sd, &readfds))
{ /* Read socket, if it was closing, else read value */
if((valread = read( sd, buffer, 1024)) == 0)
{
getpeername( sd, (struct sockaddr*)&address, (socklen_t*)&addrlen);
printf("Host disconnected, ip %s, port %d.\n", inet_ntoa(address.sin_addr), ntohs(address.sin_port));
close(sd);
clientSockets[i] = 0;
}
}
else
{
buffer[valread] = '\0';
send(sd, buffer, strlen(buffer), 0);
}
}
}
return 0;
}
If you are planning to exit your application gracefully by adding a breakstatement in your app by something similar to this:
if (exit_condition)
{
break;
}
You can place this loop at the end of your main function:
/* close connections gracefully */
closesocket(masterSocket);
masterSocket = 0; /* optional, see comment below */
for(int i = 0; i < maxClients; i++)
{
if (clientSockets[i] != 0)
{
shutdown(clientSockets[i]);
closesocket(clientSockets[i]);
clientSockets[i] = 0; /* optional, except if you also have a SIGINT handler */
}
}
If you want to do the same to handle an exit with Ctrl-C, you will find details on how to setup a SIGINT handler to handle Ctr-C here:
Catch Ctrl-C in C. Place the above loop in your handler, then. Your sockets-related variables will have to be declared at global scope, since your sockets are only visible from main() in your current code.
I have a TCP application written in C++, where a client and a server exchange data. I've istantiated a socket, believing that it would have been blocking by default; on the contrary, after server waits for a client, I have that client calls the recv function without waiting for data. This is the code in which I inizialize the socket fr the client.
int TCPreceiver::initialize(char* address, int port)
{
sock = socket (AF_INET, SOCK_STREAM, 0);
cout << "Socket: " << sock << endl;
sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons (port);
target.sin_addr.s_addr = inet_addr(address);
int fails=0;
while (connect(sock, (sockaddr*) &target, sizeof(target)) == -1)
{
fails++;
if (fails==10)
{
close(sock);
cout << "Error with connection to the server, try again"<< endl;
exit(-1);
}
}
cout << "Client connected (control channel)" << endl;
unsigned char text[10]; //Request message
//fill text[]
if(send(sock, (char*)text, 10, 0)==-1)
{
printf("send() failed with error code : %d" , -1);
exit(EXIT_FAILURE);
}
return 0;
}
I've tried adding this code:
int opts;
opts = fcntl(sock,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
exit(0);
}
opts = (opts & (~O_NONBLOCK));
if (fcntl(sock,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
exit(0);
}
but it still doesn't work, and if I call the recv(), the application doesn't block (and recv() always returns 0). Here is the function where I call the recv():
void TCPreceiver::receive(char* text, int& dim)
{
int ret;
ret = recv(sock, text, dim, 0);
dim=ret;
if(ret == -1){
printf("recv() failed with error (%d)\n", ret);
//system("PAUSE");
exit(1);
}
}
Where am I wrong?
recv() returning zero indicates either (1) you passed a zero length, which is just a programming error which I won't discuss further here, or (2) end of stream. The peer has close the connection. This isn't a non-blocking situation, this is the end of the connection. You must close the socket and stop using it. It will never return anything. It zero ever again.
See the man pages.
I am having a problem with a tcp server. I would like to listen on multiple ports to respond to clients. It should be a kind of event based. Each port indicates another type of response. I read a lot about epoll, poll, select or multithreading. I tried to work with a lot of examples from books like Unix Network Programming. But probably I need a few trigger keywords. How could I start properly?
Hopefully my questions are easy to understand.
Appreciate each answer!
TO NARROW IT DOWN THERE IS MY IDEA...
I started thinking of this:
If I am have a "Server Manager" with a lot of Server, can I do it as follows?
CreateSockets(ServerList);
CheckSockets(SocketList, master_set);
Within the Server Manager:
1) for loop to create all server sockets (functions: socket/setsockopt/ioctl/bind/listen)
void CreateSockets(map<int,ServerType> ServerList)
{
fd_set master_set;
map<int,ServerType>::iterator it;
map<int,int> SocketList;
for (it= ServerList.begin();it!= ServerList.end();it++)
{
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_sd < 0)
{
perror("socket() failed");
exit(-1);
}
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < 0)
{
perror("setsockopt() failed");
close(listen_sd);
exit(-1);
}
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < 0)
{
perror("ioctl() failed");
close(listen_sd);
exit(-1);
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = ((*it).second->Port);
rc = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
if (rc < 0)
{
perror("bind() failed");
close(listen_sd);
exit(-1);
}
rc = listen(listen_sd, 32);
if (rc < 0)
{
perror("listen() failed");
close(listen_sd);
exit(-1);
}
SocketList.insert(make_pair(((*it).second->Port),listen_sd));
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set);
}
}
Next:
2) Some how wait for some events within the server manager (Select with a list of socket descriptors)
void CheckSockets(map<int,int> SocketList, fd_set master_set)
{
fd_set working_set;
do
{
memcpy(&working_set, &master_set, sizeof(master_set));
ready_descriptors = select(max_sd + 1, &working_set, NULL, NULL, NULL);
if (ready_descriptors >0)
{
desc_ready = rc;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
if (FD_ISSET(i, &working_set))
{
desc_ready -= 1;
if (i == listen_sd)
{
do
{
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < 0)
{
//error
}
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd;
} while (new_sd != -1);
}
else
{
do
{
//Go into server and recv and send ( Input Parameter = i)
CheckServer(i);
} while (TRUE);
}
}
}
}
else {endserver=true;}
}while(endserver=true;)
}
3) Go into the server and process the question (recv/send)????
void CheckServer( int sd)
{
rc = recv(sd, buffer, sizeof(buffer), 0);
//some stuff in between
rc = send(i, buffer, len, 0);
}
Could this work?
Some parts are used and changed from the IBM nonblocking IO source Code.
thank you for all your help. I was able to get something done, BUT one thing still dont work.
What I did until now:
1) The consrtuctor of the individual server includes the socket operation.
2) I am able to return the socket id and save it within the server manager.
3) The manager has a for loop which contains the select command to check for any event on the sockets.
4) if something happens, all affected socket will sequentially repsond.
My problem is:
It works fine if I am always connect and disconnect while i am requesting data from the server.
When my client is configured in a way that the connection will be hold, everything is blocking, since my code is waiting for a disconnect.
Here are the code snippets for each part:
1)
Server::Server()
{
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
ret = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,(char *)&on, sizeof(on));
ret = ioctl(listen_sd, FIONBIO, (char *)&on);
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(Server_Port);
ret = bind(listen_sd,(struct sockaddr *)&addr, sizeof(addr));
ret = listen(listen_sd, 32);
Socket = listen_sd;
}
2)
Socket= new_Server->GetSocket();
SocketList.insert(make_pair(Socket,new_Server->ServerID));
3)
while (TRUE)
{
FD_ZERO(&working_set);
for (i=0;i < max_conn;i++)
{
if (SocketArray[i] >= 0) {FD_SET(SocketArray[i], &working_set);}
}
ret = select(max_sd+1, &working_set, NULL, NULL, NULL);
desc_ready= ret;
for (i=0; i <= max_sd && desc_ready > 0; ++i)
{
if (FD_ISSET(i, &working_set)) //jeder Peer der was hat
{
desc_ready -= 1;
//delete all loops to get the correct object
(Server).second->DoEvent(i);
}
}
}
4)
new_sd = accept(new_sd, NULL, NULL);
if (new_sd < 0)
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
}
}
do
{
rc = recv(new_sd, buffer, sizeof(buffer), 0);
//edit datastream and create response
rc = send(new_sd, buffer, len, 0);
if (rc < 0)
{
perror(" send() failed");
close_conn = TRUE;
break;
}
}while (TRUE);
I just delete the errorhandling dor listen/bind etc. just to shorten the code here... Originally it is in there.
Roughly here are the steps: You can have multiple TCP servers (aka server sockets) listen for each port. Next, you can use a select() and pass file descriptors for each of these server sockets. If you get a connection on any of these, then select would return a read event and mark the fd of the server socket that has the connection. YOu would need to call accept() on that server fd.
YOu cannot make a single TCP socket listen on multiple ports.