TCP-соединения идентифицируются по IP-адресу и номеру порта обоих концов соединения. Поэтому хорошо иметь множество клиентов (которые обычно имеют произвольно назначенные номера портов) для подключения к одному порту сервера.
Вы создаете сокет и bind()
его подключаете к порту, к которому нужно listen()
, а затем ждете, пока клиенты не постучат в него. Если вы не возражаете против блокирования, вы можете просто позвонить по номеру accept()
напрямую, но вам не удастся выполнить цикл тайм-аута или что-то еще. В противном случае вы можете select()
на сокете прослушивания, который станет читаемым, когда клиент пытается подключиться, и затем вызвать accept()
.
accept()
вернет вновь созданный сокет, который является фактическим сокетом для общения с клиентом. Исходное гнездо прослушивания продолжает прослушивать, и на него можно принимать больше соединений.
Обычно используется цикл select()
для поиска удобочитаемости на слушающем сокете и любом из подключенных сокетов. Затем, когда возвращается select()
, вы просто проверяете, является ли сокет прослушивания доступным для чтения, и если да, то accept()
; в противном случае ищите читаемый подключенный разъем и обрабатывайте его.
fd_set fds;
int max = 0, reuse = 1;
struct timeval tv;
int server;
std::vector<int> connected;
// create server listening socket
server = socket(PF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto);
setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)); // optional, but recommended
if (bind(server, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) {
// error, could not bind server socket
}
if (listen(server, 8) < 0) {
// error, could not listen on server port
}
// loop looking for connections / data to handle
while (running) {
FD_ZERO(&fds);
FD_SET(server, &fds);
if (server >= max) max = server + 1;
for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
FD_SET(*it, &fds);
if (*it >= max) max = *it + 1;
}
tv.tv_sec = 2; tv.tv_usec = 0;
if (select(max, &fds, NULL, NULL, &tv) > 0) {
// something is readable
if (FD_ISSET(server, &fds)) {
// it's the listener
connected.push_back(accept(server, (struct sockaddr *)&addr));
}
for (std::vector<int>::iterator it = connected.begin(); it != connected.end(); ++it) {
if (FD_ISSET(*it, &fds)) {
// handle data on this connection
}
}
}
}