Вот реализация однопоточного сервака, и никто не блокирует и сервак остановить не проблема
#include <windows.h>
#define WS_VERSION_REQD 0x0101
#define SZ_MAX_HOST_NAME 256
#define SZ_MAX_BUFF 1024
#define SOCKET_ID 0x3737
char lpsMyHostName [SZ_MAX_HOST_NAME];
// Имя евента
char* EvExitName = "ChatExitEvent";
SOCKET srvSocket = INVALID_SOCKET;
// тайм аут для select чтоб он не блокировал
timeval tout = {0,500};
// буфер для приема
char buffer[SZ_MAX_BUFF];
// структура описывающая подключеный узел
struct USERS {
SOCKET skt;
}users [FD_SETSIZE];
int InitChat ();
int InitUndoChat ();
int DoChat ();
int DoAccept ();
int DoReceive ();
int DoSend (int to_send);
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
HANDLE EvExit;
// попробуем сначала открыть евент
EvExit = OpenEvent (EVENT_MODIFY_STATE, false , EvExitName);
if (!lstrcmpi (lpCmdLine, "exit")){
// отсигналить выход сервака
if (EvExit){ // если сервер запущен
SetEvent (EvExit); // выставить евент
CloseHandle (EvExit);
}
return 0;
}
// если евент открылся, значит мы имеем уже запущенный сервак
if (EvExit){CloseHandle (EvExit); return 0;} // так что выходим
// создаем евент
EvExit = CreateEvent(NULL, true, false, EvExitName);
if (EvExit){ // если создался
if (InitChat ()) // инициализация чата
while (WaitForSingleObject (EvExit, 10) != WAIT_OBJECT_0) // пока не выставлен евент
if (!DoChat ()) break; // чатимси
InitUndoChat (); // деинициализировать сервак
CloseHandle (EvExit); // закрыть евент
}
return 0;
}
//---------------------------------------------------------------------------
// иниуиализация сервака
int InitChat()
{
WSADATA stWSAData;
struct hostent*lpHostInfo;
// инициализация масива сокетов
for (register i = 0; i < FD_SETSIZE; i++) users
.skt = INVALID_SOCKET;
if (WSAStartup(WS_VERSION_REQD, &stWSAData) == 0) // запрашиваем winsock2.dll
if ( gethostname(lpsMyHostName, SZ_MAX_HOST_NAME) != SOCKET_ERROR ) // имя нашего хоста
if ((lpHostInfo = gethostbyname(lpsMyHostName)) != NULL) // запрос информации о нашем хосте
// открываем слушающий сокет
if ((srvSocket = socket(PF_INET, SOCK_STREAM, 0)) != INVALID_SOCKET){
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(SOCKET_ID);
sin.sin_addr.s_addr = *(long*)lpHostInfo->h_addr_list[0];
// биндим его т.е. привязываем к номеру порта
if (bind (srvSocket, (LPSOCKADDR)&sin, sizeof(sin)) != SOCKET_ERROR)
// выставляем на прослушку
if (listen (srvSocket, 5) != SOCKET_ERROR) return 1;
}
return 0;
}
// деинициализация сервака
int InitUndoChat ()
{
// закрываем все соединения
for (register i = 0; i < FD_SETSIZE; i++)
if (users.skt != INVALID_SOCKET) closesocket (users.skt);
// закроем слушающий сокет
if (srvSocket == INVALID_SOCKET) closesocket (srvSocket);
WSACleanup (); // освобождаем winsock2.dll библиотеку
return 1;
}
// основная процедура чата
int DoChat ()
{
DoAccept (); // проверить запросы на конект
DoReceive (); // прием и и отсылка всем узлам сообщений
return 1;
}
// проверить запросы на конект
int DoAccept ()
{
int i;
FD_SET readfds;
FD_ZERO ( &readfds ); // обнулить структуру
FD_SET ( srvSocket, &readfds ); // занести слушающий сокет в структуру
// если есть запрос на конект
if (select (0, &readfds, NULL, NULL, &tout) > 0){
SOCKET skt = accept (srvSocket, NULL, NULL );
for (i = 0; i < FD_SETSIZE; i++)// ищем свободную структуру
if (users.skt == INVALID_SOCKET){
users.skt = skt;
break;
}
// если нкт свободных, закрываем соединение
if (i == FD_SETSIZE) closesocket (skt);
}
return 1;
}
// прием данных из сети
int DoReceive ()
{
int count = 0; // количество подключенных узлов
FD_SET readfds;
FD_ZERO ( &readfds );
for (register i = 0; i < FD_SETSIZE; i++)
if (users.skt != INVALID_SOCKET){
FD_SET ( users.skt, &readfds );
count++;
}
if (count) // если есть подключенные узлы
// проверить на готовность к чтению
if ((count = select (0, &readfds, NULL, NULL, &tout)) > 0)
for (register i = 0; i < FD_SETSIZE && count; i++)
if (users.skt != INVALID_SOCKET)
if (FD_ISSET (users.skt, &readfds)){
// прием данных
int err = recv (users.skt, buffer, SZ_MAX_BUFF, 0);
if (err > 0) DoSend (err); // если чтото приняли, отослать всем
// в противном случае, ошибка или узел отключился
// закрываем сокет
else{ closesocket (users.skt); users.skt = INVALID_SOCKET;}
count--;
}
return 1;
}
int DoSend (int to_send)
{
for (register i = 0; i < FD_SETSIZE; i++)
if (users.skt != INVALID_SOCKET){
send (users.skt, buffer, to_send, 0);
}
return 1;
}