Konkurentní server v C++
Konkurentní server dokáže obsloužit více klientů zároveň. V mém kódu je tohoto požadavku dosaženo použitím systémového volání fork(), které slouží k vytvoření nového procesu. Stejné funkčnosti se dá docílit i pomocí jiných metod, mimo jiné použitím vláken, či funkcí select() a poll() z knihovny pro práci se sockety.
Na server se můžete připojit například pomocí telnetu příkazem:
telnet 127.0.0.1 1234
Proč tento snippet vznikl?
V rámci druhého projekt do kurzu Počítačové komunikace a sítě (účelem bylo navrhnout protokol pro přenos souborů a implementovat klienta a konkurentní server, využívající tento protokol).
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string>
#include <arpa/inet.h>
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <sstream>
using namespace std;
const int OK = 0;
const int ERR = 1;
const int PORT = 1234;
const int MAXHOSTNAME = 200;
const int MAXCONNECTIONS = 5;
const int MAXRECV = 500;
const int SEC = 12;
const string MESS = "HELLO, YOU ARE CONNECTED TO HELLO SEVERn";
const string BYE = "Byen";
void wait ( int seconds )
{
clock_t endwait = clock () + seconds * CLOCKS_PER_SEC ;
while ( clock() < endwait ) {}
}
int main()
{
cout << "Hello I'am Hello server!" << endl <<
"My IP: 127.0.0.1 and port: " << PORT << endl;
// 0.0 Variables
int m_sock;
sockaddr_in m_addr;
// 1.0 Create socket
// 1.1 Create
m_sock = socket(AF_INET, SOCK_STREAM, 0);
if ( m_sock == -1 )
return ERR;
// 1.1.1 Allows other socket bind to this port
// (get around "Bind: Address already in use" error)
int on = 1;
if ( setsockopt (m_sock, SOL_SOCKET, SO_REUSEADDR,
(const char*) &on, sizeof(on)) )
return ERR;
// 1.2 Bind
m_addr.sin_family = AF_INET;
m_addr.sin_addr.s_addr = INADDR_ANY;
m_addr.sin_port = htons(PORT);
if ( ::bind(m_sock, (struct sockaddr*) &m_addr, sizeof(m_addr)) )
return ERR;
// 1.3 Listen
if ( ::listen ( m_sock, MAXCONNECTIONS ) )
return ERR;
// 2.0 Server body
while ( true ) {
// 2.1 Local variables
int client_m_sock;
int client_m_addr;
// 2.2 Accept connection
int addr_length = sizeof (client_m_addr);
client_m_sock = ::accept (m_sock, (sockaddr*) &client_m_addr,
(socklen_t*) &addr_length);
if (client_m_sock <= 0)
return ERR;
// 2.3 Fork
if (!fork()) { // Child (Service for a client)
close(m_sock);
write (client_m_sock, MESS.data(), MESS.length());
for (int x = 0; x < SEC; x++) { // Countdown
wait(1);
stringstream out; // ----
out << x; // Converting integer
string count; // to string.
count = out.str(); // ----
count.append("n");
write(client_m_sock, count.data(), count.length());
}
write(client_m_sock, BYE.data(), BYE.length());
close (client_m_sock);
exit(OK);
}
close(client_m_sock);
}
return OK;
}