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; }