Szustarol Temat założony przez niniejszego użytkownika |
std::thread zamiast fork(), jak się za to zabrać? » 2018-01-13 09:31:44 Witam! Mam prosty serwer echo: #include <iostream> #include <arpa/inet.h> #include <netinet/in.h> #include <stdlib.h> #include <errno.h> #include <unistd.h>
#define ERR_QUIT
int Socket( int domain, int type, int protocol ) { int rv = socket( domain, type, protocol ); if( rv == - 1 ) { std::cerr << "Error while socketing: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Listen( int feed, int queue_size ) { int rv = listen( feed, queue_size ); if( rv == - 1 ) { std::cerr << "Error while listening: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Accept( int socketFeed, sockaddr * addressStructure, socklen_t * sizeStype ) { int rv = accept( socketFeed, addressStructure, sizeStype ); if( rv == - 1 ) { std::cerr << "Error while accepting connection: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Close( int desc ) { int rv = close( desc ); if( rv == - 1 ) { std::cerr << "Error while closing: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
pid_t Fork() { pid_t rv = fork(); if( rv == - 1 ) { std::cerr << "Error while forking: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
ssize_t Writen( int desc, const void * vptr, size_t ammount ) { size_t nleft = ammount; ssize_t nwritten; const char * ptr; ptr =( char * ) vptr; while( nleft > 0 ) { if(( nwritten = write( desc, ptr, nleft ) ) <= 0 ) { if( nwritten < 0 && errno == EINTR ) nwritten = 0; else { std::cerr << "Errno: " << errno << std::endl; return - 1; } } nleft -= nwritten; ptr += nwritten; } return nwritten; }
int ProcessRequest( int feed ) { ssize_t n; char buffer[ 4096 ]; for(;; ) { while(( n = read( feed, buffer, 4096 ) ) > 0 ) { Writen( feed, buffer, n ); } if( n < 0 && errno == EINTR ) continue; else if( n < 0 ) { std::cerr << "Read error" << std::endl; } break; } }
int main() { unsigned ServerPort = 7; int listenFeed, connectionFeed; pid_t childProcessID; socklen_t clientSize; sockaddr_in clientAddressStructure = { }, ServerAddressStructure = { }; listenFeed = Socket( AF_INET, SOCK_STREAM, 0 ); ServerAddressStructure.sin_family = AF_INET; ServerAddressStructure.sin_addr.s_addr = htonl( INADDR_ANY ); ServerAddressStructure.sin_port = htons( ServerPort ); int status; do { status = bind( listenFeed,( sockaddr * ) & ServerAddressStructure, sizeof( ServerAddressStructure ) ); if( status == - 1 ) { std::cout << errno << std::endl; if( errno == EACCES ) { std::cerr << "No permission to bind to port " << ServerPort << std::endl; } else if( errno == EADDRINUSE ) { std::cerr << "This port is already occupied" << std::endl; } else { std::cerr << "Unknown error " << errno << std::endl; exit( errno ); } std::cout << "Trying port " << ++ServerPort << std::endl; ServerAddressStructure.sin_port = htons( ServerPort ); } } while( status < 0 ); Listen( listenFeed, 1024 ); std::cout << "Server running on port " << ServerPort << std::endl; for(;; ) { clientSize = sizeof( clientAddressStructure ); if(( connectionFeed = accept( listenFeed,( sockaddr * ) & clientAddressStructure, & clientSize ) ) < 0 ) { if( errno == EINTR ) continue; else; std::cerr << "Accept error" << std::endl; } std::cout << "Connection accepted" << std::endl; if(( childProcessID = Fork() ) == 0 ) { Close( listenFeed ); std::cout << "Processing request" << std::endl; ProcessRequest( connectionFeed ); std::cout << "Finishing request" << std::endl; exit( 0 ); } Close( connectionFeed ); } return 0; }
Chciałbym zamienić fork() na std::thread, aby uczynić aplikację bardziej multiplatformową oraz wplątać C++ do tych starych unixowych funkcji, jednak nie mam pojęcia jak się za to zabrać. Po krótce stworzyłem coś takiego, ale wywala sigfaulta, czy mógłby ktoś wesprzeć merytorycznie, co powinienem zrobić? (np. stworzyć najpierw wątek, potem coś z nim jeszcze zrobić itp. Byłbym wdzięczny za pomoc, moja dotychczasowa próba: #include <iostream> #include <arpa/inet.h> #include <netinet/in.h> #include <stdlib.h> #include <thread> #include <errno.h> #include <unistd.h>
#define ERR_QUIT
int Socket( int domain, int type, int protocol ) { int rv = socket( domain, type, protocol ); if( rv == - 1 ) { std::cerr << "Error while socketing: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Listen( int feed, int queue_size ) { int rv = listen( feed, queue_size ); if( rv == - 1 ) { std::cerr << "Error while listening: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Accept( int socketFeed, sockaddr * addressStructure, socklen_t * sizeStype ) { int rv = accept( socketFeed, addressStructure, sizeStype ); if( rv == - 1 ) { std::cerr << "Error while accepting connection: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
int Close( int desc ) { int rv = close( desc ); if( rv == - 1 ) { std::cerr << "Error while closing: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
pid_t Fork() { pid_t rv = fork(); if( rv == - 1 ) { std::cerr << "Error while forking: " << errno << std::endl; #ifdef ERR_QUIT exit( errno ); #endif } return rv; }
ssize_t Writen( int desc, const void * vptr, size_t ammount ) { size_t nleft = ammount; ssize_t nwritten; const char * ptr; ptr =( char * ) vptr; while( nleft > 0 ) { if(( nwritten = write( desc, ptr, nleft ) ) <= 0 ) { if( nwritten < 0 && errno == EINTR ) nwritten = 0; else { std::cerr << "Errno: " << errno << std::endl; return - 1; } } nleft -= nwritten; ptr += nwritten; } return nwritten; }
int ProcessRequest( int feed ) { ssize_t n; char buffer[ 4096 ]; std::cout << "Processing request on feed: " << feed << std::endl; for(;; ) { while(( n = read( feed, buffer, 4096 ) ) > 0 ) { Writen( feed, buffer, n ); } if( n < 0 && errno == EINTR ) continue; else if( n < 0 ) { std::cerr << "Read error" << std::endl; } break; } std::cout << "Connnection on feed: " << feed << "is finished" << std::endl; Close( feed ); }
int main() { unsigned ServerPort = 7; int listenFeed, connectionFeed; pid_t childProcessID; socklen_t clientSize; sockaddr_in clientAddressStructure = { }, ServerAddressStructure = { }; listenFeed = Socket( AF_INET, SOCK_STREAM, 0 ); ServerAddressStructure.sin_family = AF_INET; ServerAddressStructure.sin_addr.s_addr = htonl( INADDR_ANY ); ServerAddressStructure.sin_port = htons( ServerPort ); int status; do { status = bind( listenFeed,( sockaddr * ) & ServerAddressStructure, sizeof( ServerAddressStructure ) ); if( status == - 1 ) { std::cout << errno << std::endl; if( errno == EACCES ) { std::cerr << "No permission to bind to port " << ServerPort << std::endl; } else if( errno == EADDRINUSE ) { std::cerr << "This port is already occupied" << std::endl; } else { std::cerr << "Unknown error " << errno << std::endl; exit( errno ); } std::cout << "Trying port " << ++ServerPort << std::endl; ServerAddressStructure.sin_port = htons( ServerPort ); } } while( status < 0 ); Listen( listenFeed, 1024 ); std::cout << "Server running on port " << ServerPort << std::endl; for(;; ) { clientSize = sizeof( clientAddressStructure ); if(( connectionFeed = accept( listenFeed,( sockaddr * ) & clientAddressStructure, & clientSize ) ) < 0 ) { if( errno == EINTR ) continue; else; std::cerr << "Accept error" << std::endl; } std::cout << "Connection accepted" << std::endl; std::thread req( ProcessRequest, connectionFeed ); } return 0; }
|