Здравствуйте. Я тут немного копаюсь в цпп сокетах. Написал вот такой код. После того как я посылаю прерывание Ctrl^C, он пишет мне что функция закрывания вызвалась и все ок. Но если я после этого пытаюсь запустить приложение снова, то в течении где-то полминуты порт недоступен. Я как-то неправильно закрываю сокет?
#include <iostream>
#include <string>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <thread>
#include <mutex>
#include <set>
#include <chrono>
using namespace std;
class server_exception : public exception {
public:
string message;
server_exception(string m) : message(m) {}
};
#define BUF_LEN 1024
#define WITH_MUTEX(mutex, action) {mutex.lock(); action; mutex.unlock();};
bool global_stop_signal = false;
class server {
private:
bool opened = false;
set<thread::id> client_threads;
mutex client_mutex;
int listener = -1;
void client(int socket) {
WITH_MUTEX(client_mutex, client_threads.insert(this_thread::get_id()));
char buf[BUF_LEN];
int bytes_readed;
string message;
do {
bytes_readed = recv(socket, (void*)buf, BUF_LEN, 0);
int signal_on = -1;
for(int i=0; i<bytes_readed; ++i) {
if(buf[i] == '\n') {
signal_on = i;
break;
}
}
if(signal_on == -1)
message += buf;
else {
if(signal_on != 0 && buf[signal_on - 1] == 13)
signal_on--;
for(int i=0; i<signal_on; ++i)
message += buf[i];
bytes_readed = 0;
}
} while (bytes_readed > 0);
cout << "message received: \"" << message << "\"" << endl;
sprintf(buf, "received %d len message\n", static_cast<int>(message.size()));
send(socket, buf, strlen(buf), 0);
close(socket);
WITH_MUTEX(client_mutex, client_threads.erase(this_thread::get_id()));
}
public:
void run(unsigned short port) {
opened = true;
listener = socket(AF_INET, SOCK_STREAM, 0);
if(listener < 0) {
throw server_exception("listener not open");
}
sockaddr_in addr;
bzero((char*)&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
cout << "connect on " << INADDR_ANY << " " << port << endl;
if(bind(listener, (sockaddr*) &addr, sizeof(addr)) < 0) {
throw server_exception("bind error");
}
// now on port
listen(listener, 10);
for(;;) {
if(global_stop_signal) {
return;
}
// use accept4(listener, NULL, NULL, SOCK_NONBLOCK)
int socket = accept(listener, NULL, NULL);
if(socket < 0) {
throw server_exception("accept error");
} else {
thread client_thread(&server::client, this, socket);
client_thread.detach();
}
}
}
~server() {
if(opened)
stop();
}
void stop() {
if(!opened)
return;
opened = false;
cerr << "close call" << endl;
while(client_threads.size() > 0)
this_thread::sleep_for(chrono::milliseconds(100));
if(listener >= 0)
close(listener);
}
};
void ctrl_c_event(int _) {
global_stop_signal = true;
}
int main() {
struct sigaction handler;
handler.sa_handler = ctrl_c_event;
sigemptyset(&handler.sa_mask);
handler.sa_flags = 0;
sigaction(SIGINT, &handler, NULL);
server serv;
try {
serv.run(8080);
} catch (server_exception exc) {
cout << "exception: " << exc.message << endl;
}
serv.stop();
return 0;
}