1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
#include <stdio.h>
#include <string.h> //strlen
#include <stdlib.h>
#include <errno.h>
#include <unistd.h> //close
#include <arpa/inet.h> //close
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h> //FD_SET, FD_ISSET, FD_ZERO macros
#include <vector>
#include <string>
#include <sstream>
#define TRUE 1
#define FALSE 0
#define PORT 8888
struct ClientState
{
ClientState() :
sock(-1),
loggedin(false)
{
}
ClientState(int s) :
sock(s),
loggedin(false)
{
}
int sock;
bool loggedin;
std::string user;
};
int main(int argc , char *argv[])
{
struct sockaddr_in address;
std::vector<ClientState> client_socket;
//create a master socket
int master_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (master_socket < 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//set master socket to allow multiple connections , this is just a good habit, it will work without this
int opt = TRUE;
if (setsockopt(master_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0)
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
//type of socket created
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(PORT);
//bind the socket to localhost port 8888
if (bind(master_socket, (struct sockaddr *)&address, sizeof(address)) < 0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
printf("Listener on port %d \n", PORT);
//try to specify maximum of 3 pending connections for the master socket
if (listen(master_socket, 5) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
puts("Waiting for connections ...");
while (TRUE)
{
//set of socket descriptors
fd_set readfds;
FD_ZERO(&readfds); //clear the socket set
FD_SET(master_socket, &readfds); //add master socket to set
int max_sd = master_socket;
//add child sockets to set
for (size_t i = 0; i < client_socket.size(); ++i)
{
FD_SET(client_socket[i].sock, &readfds);
max_sd = std::max(max_sd, client_socket[i].sock);
}
//wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
int activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);
if ((activity < 0) && (errno != EINTR))
{
printf("select error");
}
//else its some IO operation on some other socket :)
for (std::vector<ClientState>::iterator p = client_socket.begin(); p != client_socket.end(); )
{
char buffer[1024]; //data buffer of 1K
if (FD_ISSET(p->sock, &readfds))
{
//Check if it was for closing , and also read the incoming message
int valread = recv(p->sock, buffer, sizeof(buffer), 0);
if (valread <= 0)
{
//Somebody disconnected , get his details and print
socklen_t addrlen = sizeof(address);
getpeername(p->sock, (struct sockaddr*)&address, (socklen_t*)&addrlen);
printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(address.sin_addr) , ntohs(address.sin_port));
//Close the socket and mark as 0 in list for reuse
close(p->sock);
p = client_socket.erase(p);
}
//Echo back the message that came in
else
{
// is user logged in?
if (!p->loggedin)
{
const char *message ="username:";
send(p->sock , message , strlen(message), 0);
int n = recv(p->sock, buffer, sizeof(buffer), 0);
if (n > 2) // account for trailing \r\n
{
p->loggedin = true;
p->user.assign(buffer, n - 2);
std::ostringstream os;
os << "Welcome " << p->user << " to our server, no password required\r\n";
std::string str = os.str();
send(p->sock, &str[0], str.size(), 0);
}
}
++p;
}
}
else
{
++p;
}
}
//If something happened on the master socket , then its an incoming connection
if (FD_ISSET(master_socket, &readfds))
{
//accept the incoming connection
socklen_t addrlen = sizeof(address);
int new_socket = accept(master_socket, (struct sockaddr *)&address, (socklen_t*)&addrlen);
if (new_socket < 0)
{
perror("accept");
exit(EXIT_FAILURE);
}
//inform user of socket number - used in send and receive commands
printf("New connection , socket fd is %d , ip is : %s , port : %d \n", new_socket, inet_ntoa(address.sin_addr), ntohs(address.sin_port));
//send new connection greeting message
const char *message = "Welcome to the server\r\n";
if (send(new_socket, message, strlen(message), 0) != strlen(message))
{
perror("send");
}
puts("Welcome message sent successfully");
//add new socket to array of sockets
client_socket.push_back(new_socket);
}
}
return 0;
}
|