Skip to content

Instantly share code, notes, and snippets.

@codehoose
Created December 23, 2018 16:30
Show Gist options
  • Save codehoose/49f206c7253dc9b4507b56f25d18c2e5 to your computer and use it in GitHub Desktop.
Save codehoose/49f206c7253dc9b4507b56f25d18c2e5 to your computer and use it in GitHub Desktop.
#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, &copy, nullptr, nullptr, nullptr);
// Loop through all the current connections / potential connect
for (int i = 0; i < socketCount; i++)
{
// Makes things easy for us doing this assignment
SOCKET sock = copy.fd_array[i];
// Is it an inbound communication?
if (sock == listening)
{
// Accept a new connection
SOCKET client = accept(listening, nullptr, nullptr);
// Add the new connection to the list of connected clients
FD_SET(client, &master);
// Send a welcome message to the connected client
string welcomeMsg = "Welcome to the Awesome Chat Server!\r\n";
send(client, welcomeMsg.c_str(), welcomeMsg.size() + 1, 0);
}
else // It's an inbound message
{
char buf[4096];
ZeroMemory(buf, 4096);
// Receive message
int bytesIn = recv(sock, buf, 4096, 0);
if (bytesIn <= 0)
{
// Drop the client
closesocket(sock);
FD_CLR(sock, &master);
}
else
{
// Check to see if it's a command. \quit kills the server
if (buf[0] == '\\')
{
// Is the command quit?
string cmd = string(buf, bytesIn);
if (cmd == "\\quit")
{
running = false;
break;
}
// Unknown command
continue;
}
// Send message to other clients, and definiately NOT the listening socket
for (int i = 0; i < master.fd_count; i++)
{
SOCKET outSock = master.fd_array[i];
if (outSock != listening && outSock != sock)
{
ostringstream ss;
ss << "SOCKET #" << sock << ": " << buf << "\r\n";
string strOut = ss.str();
send(outSock, strOut.c_str(), strOut.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");
}
@gitm3abreak
Copy link

Kelly, don't you have to do a (lineno 143} FD_CLR(Listening, &Copy) also? Thanks

@codehoose
Copy link
Author

Kelly, don't you have to do a (lineno 143} FD_CLR(Listening, &Copy) also? Thanks

It will be fine because the copy is only used locally. Actually... there's probably no need to do FD_CLR(listening, &master); either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment