как сделать poll или select сервер для приема клиентов?
не могу понять как сделать сервер, в котором можно добавить нового клиента в select или poll и получать события. При том ещё и не потерять данные, если в select или poll будет установлен таймер ( или для сокета сетевые данные буферизируются, пока не закроется сокет? ). вот какой сделал код.
/*
* server.c - server for game.
* author: Naidolinskii Dmitrii
*******************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>
#include <poll.h>
#include "config.h"
/* сокет сервера */
static int sockfd;
extern struct conf conf;
struct sockaddr_in in_server;
#define DEFAULT_SIZE_POLL 65535
#define DEFAULT_SIZE_DATA 1024
struct pollfd fds[DEFAULT_SIZE_POLL];
int index_poll;
static void *thread_control_clients ( void *data ) {
while ( 1 ) {
int client = poll ( fds, DEFAULT_SIZE_POLL, -1 );
if ( client == -1 ) {
perror ( "poll" );
exit ( EXIT_FAILURE );
}
if ( client ) {
char data[DEFAULT_SIZE_DATA + 1];
read ( client, data, DEFAULT_SIZE_DATA );
printf ( "%d: %s\n", client, data );
}
}
}
/* создание потока */
void create_thread ( ) {
pthread_t t;
pthread_create ( &t, NULL, thread_control_clients, NULL );
}
void wait_client ( ) {
socklen_t soss = sizeof ( in_server );
int client = accept ( sockfd, ( struct sockaddr * ) &in_server, &soss );
}
/* конфигурация сокета */
void configure_socket ( ) {
sockfd = socket ( AF_INET, SOCK_STREAM, 0 );
if ( sockfd == -1 ) {
perror ( "socket" );
exit ( EXIT_FAILURE );
}
int ret;
{
int opt = 1;
ret = setsockopt ( sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof ( opt ) );
if ( ret == -1 ) {
perror ( "sock opt SO_REUSEPORT" );
exit ( EXIT_FAILURE );
}
}
in_server.sin_family = AF_INET;
in_server.sin_port = htons ( conf.port );
in_server.sin_addr.s_addr = 0;
ret = bind ( sockfd, ( struct sockaddr *) &in_server, sizeof ( in_server ) );
if ( ret == -1 ) {
perror ( "bind" );
exit ( EXIT_FAILURE );
}
ret = listen ( sockfd, conf.listen );
if ( ret == -1 ) {
perror ( "listen" );
exit ( EXIT_FAILURE );
}
for ( int i = 0; i < DEFAULT_SIZE_POLL; i++ ) {
fds[i].fd = s;
fds[i].events = POLLIN | POLLOUT;
}
}
Ответы (2 шт):
Автор решения: Sergey
→ Ссылка
Тот код, что Вы привели, он выглядит довольно....оригинально. На самом деле, существуют определённые (почти) стандарты, для разработки сетевых приложений. Настоятельно рекомендую посмотреть книжку
UNIX: разработка сетевых приложений. 3-е изд.
Стивенс У. Р., Феннер Б., Рудофф Э. M.
https://avidreaders.ru/book/unix-razrabotka-setevyh-prilozheniy-3-e.html
Там всё описано в деталях.
Автор решения: xverizex
→ Ссылка
Решение с epoll.
/*
* server.c - server for game.
* author: Naidolinskii Dmitrii
*******************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include "config.h"
/* сокет сервера */
static int sockfd;
extern struct conf conf;
struct sockaddr_in in_server;
int epollfd, nfds;
#define DEFAULT_SIZE_POLL 65535
#define DEFAULT_SIZE_DATA 1024
struct epoll_event ev, events[DEFAULT_SIZE_POLL];
static void *thread_control_clients ( void *data ) {
while ( 1 ) {
nfds = epoll_wait ( epollfd, events, DEFAULT_SIZE_POLL, -1 );
printf ( "nfds: %d\n", nfds );
if ( nfds == 0 ) continue;
if ( nfds == -1 ) {
perror ( "poll" );
exit ( EXIT_FAILURE );
}
for ( int i = 0; i < nfds; i++ ) {
char data[DEFAULT_SIZE_DATA + 1];
int ret = read ( events[i].data.fd, data, DEFAULT_SIZE_DATA );
if ( ret == -1 || ret == 0 ) {
epoll_ctl ( epollfd, EPOLL_CTL_DEL, events[i].data.fd, &events[i] );
continue;
}
char *s = strchr ( data, '\n' );
if ( s ) *s = 0;
s = strchr ( data, '\r' );
if ( s ) *s = 0;
data[ret] = 0;
printf ( "%d: %s\n", events[i].data.fd, data );
}
}
}
/* создание потока */
void create_thread ( ) {
epollfd = epoll_create1 ( 0 );
if ( epollfd == -1 ) {
perror ( "epoll_create" );
exit ( EXIT_FAILURE );
}
pthread_t t;
pthread_create ( &t, NULL, thread_control_clients, NULL );
}
void wait_client ( ) {
socklen_t soss = sizeof ( in_server );
int client = accept ( sockfd, ( struct sockaddr * ) &in_server, &soss );
if ( client == -1 ) return;
printf ( "%d подключен.\n", client );
ev.events = EPOLLIN;
ev.data.fd = client;
if ( epoll_ctl ( epollfd, EPOLL_CTL_ADD, client, &ev ) == -1 ) {
perror ( "epoll_ctl" );
exit ( EXIT_FAILURE );
}
}
/* конфигурация сокета */
void configure_socket ( ) {
sockfd = socket ( AF_INET, SOCK_STREAM, 0 );
if ( sockfd == -1 ) {
perror ( "socket" );
exit ( EXIT_FAILURE );
}
int ret;
{
int opt = 1;
ret = setsockopt ( sockfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof ( opt ) );
if ( ret == -1 ) {
perror ( "sock opt SO_REUSEPORT" );
exit ( EXIT_FAILURE );
}
}
in_server.sin_family = AF_INET;
in_server.sin_port = htons ( conf.port );
in_server.sin_addr.s_addr = 0;
ret = bind ( sockfd, ( struct sockaddr *) &in_server, sizeof ( in_server ) );
if ( ret == -1 ) {
perror ( "bind" );
exit ( EXIT_FAILURE );
}
ret = listen ( sockfd, conf.listen );
if ( ret == -1 ) {
perror ( "listen" );
exit ( EXIT_FAILURE );
}
}