Вопрос по компоненту - TServerSocket. Как обработать отключение юзера?
Обрабатывается событие OnGetThread:
((TClientThreadE *)SocketThread)->Resume();
Соответственно старует поток - как и должно. Функция Execute реализована следующим образом:
{
;
}
delete DataModule; //
В собитии ssOTCThreadEnd описываю:
В потоке соответственно переопределена Terminate(). Сам поток объявлен как наследник TServerClientThread. Но на сервере поток не завершается. В чем моя ошибка?
А вот если работать с асинхронными сокетами в разных потоках, то делаем так:
в событии ClientConnect создаем новый поток, переназначаем в него обработку событий сокета...
TObject *Sender, TCustomWinSocket *Socket)
{
TPOP3Thread * POP3=new TPOP3Thread(true);
POP3->FreeOnTerminate=true;
Socket->onSocketEvent=POP3->OnSocketEvent;
Socket->onErrorEvent=POP3->OnSocketErrorEvent;
POP3->Resume();
Socket->Data=POP3; // пометили сокет указателем на поток, который отвечает за работу с ним.
}
Вот и все, далее вся работа идет в потоке POP3, где и реализованы входные функции для событий сокета - OnSocketEvent и OnSocketErrorEvent
{
switch(SocketEvent)
{
case seRead:
{
POP3Read(Socket);// уходим в обработку чтения данных из сокета
return;
}
case seDisconnect:
{
POP3Disconnect(Socket);
}
// вызов обработки других событий...
}
}
P.S.
IMHO - есть сомнения насчет цикла while(!Terminated||Client->Connected)
- наверно он у тебя будет выполняться до тех пор пока оба значения не изменят свой статус на противоположный
замени || на &&.. (но может я ошибаюсь...)
Я лично так делать даже не пробовал - а зачем так ?
Спасибо за помощь. А то чегото действительно перемудрил и запутался. В своем варианте я вообще реализовал без потоков в конечном итоге (запарили! :) ). Получилось примерно такая вот байда (обработку ошибок я удалил, что бы не захламлять код) :
clientaddr;
SOCKET sServerListen;
SOCKET ClientSockets[MAX_CONNECTION];
int TotalSocket;
int iSize;
unsigned short port;
FD_SET ReadSet;
int ReadySock;
//Включаем сокет
sServerListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
ULONG ulBlock;
ulBlock = 1;
localaddr.sin_addr.s_addr = htonl(INADDR_ANY);
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
listen(sServerListen, 4);
Ну а дальше запускаем цикл и ждем гостей. Макс количество подключений задается реестр, файл настройки. Естественно такие вещи удобней загружать в службе а не в программе.
{
FD_ZERO(&ReadSet);
FD_SET(sServerListen, &ReadSet);
for (int i=0; i<TotalSocket; i++)
if (ClientSockets != INVALID_SOCKET)
FD_SET(ClientSockets, &ReadSet);
if ((ReadySock = select(0, &ReadSet, NULL, NULL, NULL)) == SOCKET_ERROR)
{ ;
}
//Смотрите кто пришел!
else if (FD_ISSET(sServerListen, &ReadSet))
{
iSize = sizeof(clientaddr);
ClientSockets[TotalSocket] = accept(sServerListen, (struct sockaddr *)&clientaddr,
&iSize);
if (ClientSockets[TotalSocket] == INVALID_SOCKET)
{
break;
}
TotalSocket++;
}
//Нам шлют приветы
for (int i=0; i<TotalSocket; i++)
{
if (ClientSockets == INVALID_SOCKET){
TotalSocket--;
continue;
}
if (FD_ISSET(ClientSockets, &ReadSet))
{
char szRecvBuff[1024];
char *szSendBuff;
int ret = recv(ClientSockets, szRecvBuff, sizeof(szRecvBuff), 0);
if (ret == 0)
{
ClientSockets=INVALID_SOCKET;
TotalSocket--;
break;
}
else if (ret == SOCKET_ERROR)
{
TotalSocket--;
break;
}
AnsiString tmp = szRecvBuff;
//Что то прочитали - проверим:
if(tmp1=="Login"){
szSendBuff = new char[tmp.Length()+2];
strcpy(szSendBuff, "Pass#\n\0");
}
...
ret = send(ClientSockets, szSendBuff, sizeof(szSendBuff), 0);
}
}
}
closesocket(sServerListen);
return ;
И если использовать потоки - то тогда необходимо формировать из их массив (я имею виду типа вектора и подобное), для того что бы можно было выполнить какие-либо операции, типа посылки сообщений всем активным юзерам?
Хотя нет в принципе. Вполне можно использовать свойство Data для получения доступа к потоку сокета, поэтому вектор тут нафиг не нужен. С этим разобрался.
И данная схема уперто не хочет почемуто работать как служба - даже интерактивная. Выдает ошибку ассинхронного сокета при подключении пользователя и баста.