Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > C/C++: Сетевое программирование > Сервсер на сокетах


Автор: Duke Nuken 27.09.04, 13:06
Вообщем пытаюсь создать нормальный сервер ка сокетах.
Проблема в том, что не могу понять как сделать accept (прием)
при конекте.
То есть, создаеться сокет, вешаеться на порт, слушает обращения, а дальше что?
Как правильно исполльзовать accept? Как обработать обращение на прослушиваемый порт?

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    WORD wVersionRequested;
    WSADATA wsaData;
     
    wVersionRequested = MAKEWORD( 2, 2 );
     
     
    // открываем сокет
       if (WSAStartup( wVersionRequested, &wsaData ))
       {
               MessageBox (NULL,"Ошибка инициализации dll",0,0);        
       }
     
     
    // создаем сокет
       SOCKET mysocket;          
       mysocket = socket(PF_INET, SOCK_STREAM, 0 );
     
    // привязываем сокет к порту
     
            SOCKADDR_IN socketaddr;
            socketaddr.sin_family = AF_INET;
            socketaddr.sin_addr.s_addr  = INADDR_ANY;
            socketaddr.sin_port = htons (17700);
     
            if (bind(mysocket,(LPSOCKADDR) &socketaddr,sizeof(socketaddr)) == SOCKET_ERROR)
            {
                    MessageBox (NULL,"Жопа",0,0);
                    exit(1);
            }
            else MessageBox (NULL,"Привязываем сокет к 17700 порту",0,0);
     
            if(listen(mysocket , 1) == SOCKET_ERROR )
            {
              MessageBox(NULL, "listen Error", "Error", MB_OK);
              return;
            }
     
            sockaddr new_sockaddr;
            int lenz_sockaddr;
        
            SOCKET newsocket = accept ( mysocket,  &new_sockaddr, &lenz_sockaddr);
            MessageBox (NULL, "Пришол вызов", 0,0);
     
    closesocket(mysocket);
     
    // закрываем сокет  
       if (WSACleanup() == 0) MessageBox (NULL,"Закрытие сокета удачно",0,0);


Такой код просто завершаеться, тоесть сокет создаться, забиндился и закрылся.
Как поставить его в режим ожидания?

Автор: bum 27.09.04, 13:30
В поток его :wall:

Автор: Duke Nuken 27.09.04, 13:45
Гм. Если чесно я не умею пока создавать потоки. Но код исправил.
Между прочим от нефиг делать зашол на msdn.microsoft.com и нашол там полностью
рабочий код. Так что всем рекомендую.

http://msdn.microsoft.com/library/default....server_code.asp

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    #include <stdio.h>
    #include "winsock2.h"
     
    void main() {
     
        // Initialize Winsock.
        WSADATA wsaData;
        int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
        if ( iResult != NO_ERROR )
            printf("Error at WSAStartup()\n");
     
        // Create a socket.
        SOCKET m_socket;
        m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
     
        if ( m_socket == INVALID_SOCKET ) {
            printf( "Error at socket(): %ld\n", WSAGetLastError() );
            WSACleanup();
            return;
        }
     
        // Bind the socket.
        sockaddr_in service;
     
        service.sin_family = AF_INET;
        service.sin_addr.s_addr = inet_addr( "127.0.0.1" );
        service.sin_port = htons( 27015 );
     
        if ( bind( m_socket, (SOCKADDR*) &service, sizeof(service) ) == SOCKET_ERROR ) {
            printf( "bind() failed.\n" );
            closesocket(m_socket);
            return;
        }
        
        // Listen on the socket.
        if ( listen( m_socket, 1 ) == SOCKET_ERROR )
            printf( "Error listening on socket.\n");
     
        // Accept connections.
        SOCKET AcceptSocket;
     
        printf( "Waiting for a client to connect...\n" );
        while (1) {
            AcceptSocket = SOCKET_ERROR;
            while ( AcceptSocket == SOCKET_ERROR ) {
                AcceptSocket = accept( m_socket, NULL, NULL );
            }
            printf( "Client Connected.\n");
            m_socket = AcceptSocket;
            break;
        }
        
        // Send and receive data.
        int bytesSent;
        int bytesRecv = SOCKET_ERROR;
        char sendbuf[32] = "Server: Sending Data.";
        char recvbuf[32] = "";
        
        bytesRecv = recv( m_socket, recvbuf, 32, 0 );
        printf( "Bytes Recv: %ld\n", bytesRecv );
        
        bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 );
        printf( "Bytes Sent: %ld\n", bytesSent );
     
        return;
    }

Автор: Muran 27.09.04, 14:01
Цитата Duke Nuken, 27.09.04, 16:45
AcceptSocket = SOCKET_ERROR;
while ( AcceptSocket == SOCKET_ERROR ) {
AcceptSocket = accept( m_socket, NULL, NULL );
}


за одно вот это автору надо оторвать руки...
чему они учат??

этож какая загрузка проца идет..

поищи на форуме по поводу WSAEventSelect.. сильная вещь и решает все проблемы..
я выкладывал готовуб потоковую функцию.. там в ней все есть..

Автор: Duke Nuken 28.09.04, 13:10
Так. Разобрался с потоками, согласен кривой метод accept в цикле крутить,
но в потоке терпимо и не жрет почти ничего. Я смотрел, код в ожидании еъст
меньше одного процента.

Нашол вот такой вот код на майкрософте с использованием WSAWaitForMultipleEvents
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
      //-----------------------------------------
      // Declare and initialize variables
      WSABUF DataBuf;
      char buffer[DATA_BUFSIZE];
      DWORD EventTotal = 0,
        RecvBytes = 0,
        Flags = 0,
        BytesTransferred = 0,
        CallBack = 0;
      WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
      WSAOVERLAPPED AcceptOverlapped;
      SOCKET ListenSocket, AcceptSocket;
     
      //-----------------------------------------
      // Initialize Winsock
      WSADATA wsaData;
      WSAStartup(MAKEWORD(2,2), &wsaData);
     
      //-----------------------------------------
      // Create a listening socket bound to a local
      // IP address and the port specified
      ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     
      sockaddr_in service;
      service.sin_family = AF_INET;
      service.sin_port = htons(17700);
     
      service.sin_addr.s_addr = htonl(INADDR_ANY);
     
      //-----------------------------------------
      // Bind the listening socket to the local IP address
      // and port number
      bind(ListenSocket, (SOCKADDR *) &service, sizeof(SOCKADDR));
     
      //-----------------------------------------
      // Set the socket to listen for incoming
      // connection requests
      listen(ListenSocket, 1);
      //printf("Listening...\n");
     
      //-----------------------------------------
      // Accept and incoming connection request
      AcceptSocket = accept(ListenSocket, NULL, NULL);
     
      //-----------------------------------------
      // Create an event handle and setup an overlapped structure.
      EventArray[EventTotal] = WSACreateEvent();
      ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
      AcceptOverlapped.hEvent = EventArray[EventTotal];
      DataBuf.len = DATA_BUFSIZE;
      DataBuf.buf = buffer;
      EventTotal++;
     
      //-----------------------------------------
      // Call WSARecv to receive data into DataBuf on
      // the accepted socket in overlapped I/O mode
      if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
      {
        if (WSAGetLastError() != WSA_IO_PENDING)
          printf("Error occurred at WSARecv()\n");
      }
     
      //-----------------------------------------
      // Process overlapped receives on the socket
      while (1) {
        DWORD Index;
     
        //-----------------------------------------
        // Wait for the overlapped I/O call to complete
        Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
     
        //-----------------------------------------
        // Reset the signaled event
        WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
     
        //-----------------------------------------
        // Determine the status of the overlapped event
        WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE, &Flags);
     
        //-----------------------------------------
        // If the connection has been closed, close the accepted socket
        if (BytesTransferred == 0) {
          printf("Closing Socket %d\n", AcceptSocket);
          closesocket(AcceptSocket);
          WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
          return;
        }
     
        //-----------------------------------------
        // If data has been received, echo the received data
        // from DataBuf back to the client
        if (WSASend(AcceptSocket, &DataBuf, 1, &RecvBytes, Flags, &AcceptOverlapped, NULL) == SOCKET_ERROR)
          printf("WSASend() is busted\n");
     
        //-----------------------------------------    
        // Reset the changed flags and overlapped structure
        Flags = 0;
        ZeroMemory(&AcceptOverlapped, sizeof(WSAOVERLAPPED));
     
        AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];
     
        //-----------------------------------------
        // Reset the data buffer
        DataBuf.len = DATA_BUFSIZE;
        DataBuf.buf = buffer;
      }


Ну тут чтото странное... Он зависает на аксепте...
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
      AcceptSocket = accept(ListenSocket, NULL, NULL);

Я тестироывал обращаясь из IE на указаный порт, получал в ответ
в броузаер чтото вроде
Цитата

GET / HTTP/1.1 Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/x-shockwave-flash, */* Accept-Language: ru Cookie: phpbb2mysql_data=a%3A2%3A%7Bs%3A11%3A%22autologinid%22%3Bs%3A32%3A%222063c1608d6e0baf80249c42e2be5804%22%3Bs%3A6%3A%22userid%22%3Bi%3A2%3B%7D; avtforum_data=a%3A0%3A%7B%7D; b=b User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; MyIE2; .NET CLR 1.1.4322) Host: 192.168.1.19:17700 Connection: close МММММММММММММММММММММММММММММММММММММММММММММММММММММММММММ...

и при дебаге скрипт оставался на строке аксепта. :blink:

Вообщем хотелбы для себя понять теорию.
Вот создал я сокет. Забиндил его на порт. Слушаю.
Потом, судя по коду выполняеться аксепт.

Потом вызываеться функция WSACreateEvent(); - создаеться событие
а дальше идет какаято ерунда смысла которой я не могу понять...
Поясните, плз.

Автор: ViGOur 28.09.04, 13:21
ТЫ немного не то нашел! :)
Просто ты нашел как работать с асинхронным вводом\выводом на сокетах.
На accept зависает так как ожидает соединения, когда какой-нибудь клиент сделает connect к данному серверу в дебаге ты пойдешь дальше...

И все же лучше использовать WSAEventSelect! ;)

Добавлено
А происходит в твоем коде вот что:
После того как принимаем соединение, мы что-то там отправляем,
в данном случае наш обьект событие находится в занятом состоянии...
После этого мы вызываем WSAWaitForMultipleEvents в котором ожидаем, когда закончится операция ввода\вывода на сокете, когда операция заканчивается, обьект событие переходит в свободное состояние. С помощью WSAGetOverlappedResult мы проверяем на сколько корректно прошла I\O операция.
Ели прошла с ошибкой, то закрываем сокет и и выходим, иначе отсылаем ккие-то там данные и читаем начиная с WSAWaitForMultipleEvents! :)

Автор: Duke Nuken 28.09.04, 13:29
to ViGOur

Слушай, поясни, будь добр, что вообще дает механизм с использованием
этих WSAEventSelect?
Ну вот когда делаеш аксепт, то там создаеться новый сокет.
С ним работаеш (принимаеш, отправляеш данные), а потом просто закрываеш этот
созданый сокет.

ТОесть схема такая.
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    socket()
    bind()
    listen()
    цикл accept()
      {
         recv с новым сокетом
         send с новым сокето
         closesocket с новым сокетом
      }


А как получаеться схема с WSAEventSelect?

Автор: Muran 28.09.04, 20:26
вот откуда-то выдрал.. старая прога... или тест.. не помню.. но вроде работает и для понимания достаточно..

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    DWORD _stdcall  ReadThread(LPVOID pParam)
    {
        SOCKET*pSock=(SOCKET*)pParam;
        WSAEVENT  wsaEvent[2];
     
      DWORD err=1,index;
      WSANETWORKEVENTS  NetworkEvents;
      DWORD EventIndex,dwErr,dwFlag=MSG_PARTIAL,dwRet,dwNum;
      char buf[BLOCK_LENGTH+4];
      WSABUF wsabuf;
      wsabuf.len=300;
      wsabuf.buf=new char[wsabuf.len];
     
      wsaEvent[0]=StopEvent;
      wsaEvent[1]=WSACreateEvent();
      WSAEventSelect(*pSock,wsaEvent[1],FD_READ|FD_CLOSE);
     
      while(err)
      {
        EventIndex=WSAWaitForMultipleEvents(2,wsaEvent,FALSE,WSA_INFINITE,FALSE);
        index=EventIndex-WSA_WAIT_EVENT_0;
        if(index==0)
          break;
        WSAEnumNetworkEvents(*pSock,wsaEvent[1],&NetworkEvents);
     
        if(NetworkEvents.lNetworkEvents&FD_READ)
        {
          if(NetworkEvents.iErrorCode[FD_READ_BIT]==0)
          {
            dwRet=WSARecv(*pSock,&wsabuf,1,&dwNum,&dwFlag,NULL,NULL/*CompletionROUTINE*/);
            dwRet=WSARecv(*pSock,&wsabuf,1,&dwNum,&dwFlag,NULL,NULL/*CompletionROUTINE*/);
            dwErr=WSAGetLastError();
                  printf("%s\n",wsabuf.buf);
     
    //               recv(*pSock,buf,BLOCK_LENGTH,0);
    //               printf("%s\n",buf);
                }
        }
     
        if(NetworkEvents.lNetworkEvents&FD_CLOSE)
        {
          if(NetworkEvents.iErrorCode[FD_CLOSE_BIT]==0)
          {
            WSACloseEvent(wsaEvent[1]);
            closesocket(*pSock);
                    delete pSock;
            return 0;
          }
        }
      }
        closesocket(*pSock);
        delete pSock;
        SetEvent(hStop[1]);
        return 0;
    }
     
     
    DWORD _stdcall EventSelect(LPVOID pParam)
    {
      SOCKET  Listen,sock;
      SOCKADDR_IN addr;
      WSAEVENT  wsaEvent[3];
     
      DWORD err=1,index,tmp;
      WSANETWORKEVENTS  NetworkEvents;
      DWORD EventIndex;
      
      Listen=socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
      if(Listen==SOCKET_ERROR)
      {
        return 0;
      }
        
      addr.sin_family=AF_INET;
      addr.sin_addr.s_addr=GetCurrentIP();
      addr.sin_port=htons(7007);
      if(bind(Listen,(PSOCKADDR)&addr,sizeof(addr))==SOCKET_ERROR)
      {
        closesocket(Listen);
        return 0;
      }
     
      wsaEvent[0]=StopEvent;
      wsaEvent[1]=WSACreateEvent();
      wsaEvent[2]=WSA_INVALID_EVENT;
      WSAEventSelect(Listen,wsaEvent[1],FD_ACCEPT|FD_CLOSE);
      listen(Listen,5);
     
      while(err)
      {
        EventIndex=WSAWaitForMultipleEvents(2,wsaEvent,FALSE,WSA_INFINITE,FALSE);
        index=EventIndex-WSA_WAIT_EVENT_0;
        if(index==0)
          break;
          WSAEnumNetworkEvents(Listen,wsaEvent[1],&NetworkEvents);
            tmp=WSAGetLastError();
        if(NetworkEvents.lNetworkEvents&FD_ACCEPT)
        {
          if(NetworkEvents.iErrorCode[FD_ACCEPT_BIT]==0)
          {
            SOCKET*pSock=new SOCKET;
                    *pSock=accept(Listen,NULL,NULL);
                    ResetEvent(hStop[1]);
                    printf("Starting clinet\n");
            CloseHandle(CreateThread(NULL,0,ReadThread,(LPVOID)pSock,0,NULL));
          }
        }
     
        if(NetworkEvents.lNetworkEvents&FD_CLOSE)
        {
    //        if(NetworkEvents.iErrorCode[FD_CLOSE_BIT]==0)
    //      {
            WSACloseEvent(wsaEvent);
            closesocket(Listen);
                  SetEvent(hStop);
            return 1;
    //      }
        }
      }
      printf("Terminated...\n");
      WSACloseEvent(wsaEvent[1]);
      closesocket(Listen);
      SetEvent(hStop[0]);
      return 0;
    }


Добавлено
1. а механизм дает возможность более гибкой работы с вводом\выодом в сокеты..
поток-оьработччик работает только когда ему есть чем заниматься..
принимать подключения, или читать даные..
все остальное время он не мешает работе других потоков..

2. всегда есть возможность прервать ожидание без TrminateThread или длитльных таймаутов простыв выставлением евента

Автор: Duke Nuken 29.09.04, 10:20
Код не рабочий (том половина переменных не определена и чему они равны не понятно)...
И так разобраться не могу, а там потоков накручено.
Как всегда - проще понять и написать свой код, чем разобраться в чужом.

Люди скажите мне вот что:

В схема с Eventam'и такая?

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    socket()
    bind()
    listen()
     
    цикл
    {  
        WSAWaitForMultipleEvents()
        
        WSAEnumNetworkEvents()
       ... и тут разбор того что за событие пришло...  
    }


1) Как я понял тут accept вообще не используеться. Да?
2) Если функция описана так
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    WSAWaitForMultipleEvents(2, &NewEvent, FALSE, WSA_INFINITE, FALSE);

И нет не одного подключения, что она вернет? Ну тоесть она замрет в ожидании как accept или
отдаст ошибку?
3) Непойму какое событие получает WSAEnumNetworkEvents если нет подключенных?

Автор: Duke Nuken_ 30.09.04, 14:14
Вообщем хотелось бы написать клиент-сервер программы чтобы при каждом обрашении на сервер
для обработки создавался отдельный сокет и он обрабатывался в отдельном потоке.

Проблема. После того как производиться привязка события к порту функцией WSAEventSelect()
функция recv() перестает коректно работать. Дело в том, что когда просто слушать порт и
после конекта вызывать recv(), то она замерает в ожидании пока не получит какие-либо данные.
А после того как на слушающий сокет вешаеться событие и не успели отправить данные, то recv()
завершаеться сразуже с результатом -1.
Почему так происходит?



<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    WORD wVersionRequested;
    WSADATA wsaData;
     
    wVersionRequested = MAKEWORD( 2, 2 );
     
    // открываем сокет
       if (WSAStartup( wVersionRequested, &wsaData ))
       {
               MessageBox (NULL,"Ошибка инициализации dll",0,0);        
       }
     
     
    // создаем сокет
       SOCKET ListenSocket;          
       ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     
    // привязываем сокет к порту
     
            SOCKADDR_IN socketaddr;
            socketaddr.sin_family = AF_INET;
            socketaddr.sin_addr.s_addr  = htonl(INADDR_ANY); //inet_addr("192.168.1.19");;
            socketaddr.sin_port = htons (17700);
     
            if (bind(ListenSocket,(SOCKADDR*) &socketaddr,sizeof(socketaddr)) == SOCKET_ERROR)
            {
                    MessageBox (NULL,"Жопа",0,0);
                    exit(1);
            }
            else MessageBox (NULL,"Привязываем сокет к 17700 порту",0,0);
     
            if(listen(ListenSocket , 1) == SOCKET_ERROR )
            {
              MessageBox(NULL, "listen Error", "Error", MB_OK);
              return 0;
            }
     
    WSAEVENT NewEvent;
     
    NewEvent = WSACreateEvent();
    WSAEventSelect ( ListenSocket,  NewEvent, FD_ACCEPT | FD_CLOSE);
     
     
    SOCKET AcceptSocket; //сокет на приемом соеденения
    char cstr[255]; // буфер приема
     
     
    //-------------------------
    // Wait for network events on all sockets
    int Index = WSAWaitForMultipleEvents(1, &NewEvent, FALSE, WSA_INFINITE, FALSE);
     
    WSAEnumNetworkEvents(ListenSocket, EventArray, &NetworkEvents);
     
     
    if( ConnectEvent.lNetworkEvents & FD_ACCEPT )
    {
        AcceptSocket = WSAAccept(ListenSocket, &saClient, &iClientSize, NULL, NULL);
     
        int recvd = recv (AcceptSocket, cstr, sizeof(cstr), 0); // получаем данные с сокета
        MessageBox (NULL, cstr, "Переданые данные",0);
     
        closesocket(AcceptSocket);
    }
     
    .......



Вот в строке int recvd = recv (AcceptSocket, cstr, sizeof(cstr), 0);
происходит глюк, потому что функция перестает ожидать что ей чтото прислали
и если есть данные она их отображает, если их нет выдает ошибку.
Почему не происходит ожидание?

Есть другой вариант, слушать события для новосозданого сокета (AcceptSocket),
но чтото странно работают эти события. Когда я ожидаю события FD_WRITE на AcceptSocket,
то оно тутже наступает. Почему спрашиваеться???

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    int Index = WSAWaitForMultipleEvents(1, &NewEvent, FALSE, WSA_INFINITE, FALSE);
     
     
    SOCKET AcceptSocket; //сокет на приемом соеденения
    char cstr[255]; // буфер приема
     
    WSAEnumNetworkEvents(ListenSocket, EventArray, &NetworkEvents);
     
     
    WSAEVENT NewEvent2;
    WSANETWORKEVENTS NetworkEvents2;
     
     
    if( ConnectEvent.lNetworkEvents & FD_ACCEPT )
    {
        AcceptSocket = accept( ListenSocket, NULL, NULL );
     
        NewEvent2 = WSACreateEvent();
     
        WSAEventSelect ( AcceptSocket,  NewEvent2, FD_WRITE);
     
        Index = WSAWaitForMultipleEvents(1, &NewEvent2, FALSE, WSA_INFINITE, FALSE);
     
    //  MessageBox (NULL, "Ожидаем передачу данных", "Сокеты",0);
     
        int recvd = recv (AcceptSocket, cstr, sizeof(cstr), 0); // получаем данные с сокета
        MessageBox (NULL, cstr, "Переданые данные",0);

Автор: UncleBob 30.09.04, 15:30
Цитата Muran, 27.09.04, 18:01
этож какая загрузка проца идет..

Нулевая. Сокеты блокирующие => accept блокируется до подключения нового клиента.

Автор: Duke Nuken 01.10.04, 07:48
Вообщем вопрос. Как следует поступать при такой схеме:

Есть сервер и клиент.
1 этап - сервер) Я создаю сокет и вешаю на него событие ACCEPT.
начинаю ожидать его функцией WSAWaitForMultipleEvents()
2 этап - клиент) Соеденяюсь с сервером. connect() и тутже отправляю данные send()
3 этап - сервер) Обрабатываю событие WSAEnumNetworkEvents() и пытаюсь
сделать accept на новый сокет.
4 этап - сервер) Пытаюсь забрать присланые на сервер данные recv()

Бред происходит в том, что если клиент сразу же после конекта отсылает данные
до того как на сервере производиться accept нового соеденения, то данные отсылаються
в никуда. ТОесть нужно успеть сделать accept на сервере. Ну ставить всякие Sleep на
клиенте этоже не дело.
Я вот не пойму никак если секет создаеться командой socket, то он изначально какой?
Синхронный или асинхронный? Я точно знаю что он блокируемый. Но вот если использовать
функцию WSAAsyncSelect() то сокет становиться не блокируемым на сервере. А если на клиенте
блокируемый? То гда что? Ни кто из них не измениться? Ну тоесть не станит из блокируемого
в не блокируемый и на оборот.

Автор: Duke Nuken_ 04.10.04, 07:29
Вообщем, провозился с этой ассинхронностью4 дня. Таки сделал.
И знаете что я думаю? Что это ПОЛНАЯ чушь. Она ничерта не дает ни в
скорости, ни в надежности, ни в ресурсоемкости...

Если писать сервак который обрабатывает много клиентов, то это делаеться просто
обычными блокируемыми сокетами. Один из них слушает в цикле и как только производиться
конект создает новый сокет функцией accept и передает его обработку в поток, а сам
возвращаеться в ожидание.

Вот 100% рабочий код на неограниченое кол-во подключений.

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
    DWORD WINAPI WorkOnSocket(LPVOID lpParam);
     
    UINT Server_Run (LPVOID pParam)
    {
     
    WORD wVersionRequested;
    WSADATA wsaData;
     
     
    wVersionRequested = MAKEWORD( 2, 2 );
     
     
    // открываем сокет
       if (WSAStartup( wVersionRequested, &wsaData ))
       {
               MessageBox (NULL,"Ошибка инициализации dll",0,0);        
       }
     
     
    // создаем сокет
       SOCKET mysocket;          
       mysocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     
    // привязываем сокет к порту
     
            SOCKADDR_IN socketaddr;
            socketaddr.sin_family = AF_INET;
            socketaddr.sin_addr.s_addr  = htonl(INADDR_ANY); //inet_addr("192.168.1.19");;
            socketaddr.sin_port = htons (17700);
     
            if (bind(mysocket,(SOCKADDR*) &socketaddr,sizeof(socketaddr)) == SOCKET_ERROR)
            {
                    MessageBox (NULL,"Жопа",0,0);
                    exit(1);
            }
            else MessageBox (NULL,"Привязываем сокет к 17700 порту",0,0);
     
            if(listen(mysocket , 1) == SOCKET_ERROR )
            {
              MessageBox(NULL, "listen Error", "Error", MB_OK);
              return 0;
            }
     
     
     
      //----------------------
      // Create a SOCKET for accepting incoming requests.
      SOCKET AcceptSocket;
     
      //----------------------
      // Accept the connection.
      while(1) {
        AcceptSocket = SOCKET_ERROR;
            while( AcceptSocket == SOCKET_ERROR )
            {
                        /* вот в этом цикле слушаеться сокет mysocket и как только
                         производиться подключение, создаеться AcceptSocket и передаеться
                         в поток. Сам mysocket возвращаеться в режим ожидания. */
              AcceptSocket = accept( mysocket, NULL, NULL );
            }
            unsigned long id;
            CreateThread ( NULL, 0, WorkOnSocket, (LPVOID) AcceptSocket, 0, &id );
     
       // break;
      }
     
      
    closesocket(mysocket);
     
    // закрываем сокет  
       if (WSACleanup() == 0) MessageBox (NULL,"Закрытие сокета удачно",0,0);
     
       return 1;
    }
     
     
     
    DWORD WINAPI WorkOnSocket(LPVOID lpParam)
    {
        char cstr[100];
     
        SOCKET client = (SOCKET) lpParam;
     
        int recvd = recv (client, cstr, sizeof(cstr), 0); //client? допустим, мы на сервере!
    //  MessageBox (NULL, cstr, "Полученые данные",0);
     
        
        char send_cstr[] = "Data get OK. Thanks you.";
        
        int sent = send (client, send_cstr, sizeof(send_cstr), 0);
     
        closesocket(client);
        
        return 1;
    }

Автор: MAxZ 08.11.04, 10:28
Duke Nuken, по поводу последнего исходника... (хотел отослать приватное сообщение, но не работает)

<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
     
        // Accept the connection.
        while(1)
        {
            AcceptSocket = SOCKET_ERROR;
            while( AcceptSocket == SOCKET_ERROR )
            {
                /* вот в этом цикле слушаеться сокет mysocket и как только
                 производиться подключение, создается AcceptSocket и передаеться
                 в поток. Сам mysocket возвращается в режим ожидания. */
                AcceptSocket = accept( mysocket, NULL, NULL );
            }
            unsigned long id;
            CreateThread ( NULL, 0, WorkOnSocket, (LPVOID) AcceptSocket, 0, &id );
            // break;
        }

по коду:
а если подключение не производится?
тогда сразу идёт создавать поток?!

глобально:
после обнаружение подключения клиентом программа создаёт отдельный поток, к-й получает поступившую на сокет информацию, так?
он работает с копией сокета или самим экземпляром сокета?

Автор: Duke Nuken 08.11.04, 11:25
Гм. Это уже устаревший код.
Я был таки не прав, сервак точно нужно на аснхронных сокетах писать.
Там все сокеты обрабатываються в одном потоке.

Чтоже до устаревшего кода, то если ты внимательно читал, то это БЛОКИРУЕМЫЕ сокеты.
И если ты все правильно сделал, то на строке
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    AcceptSocket = accept( mysocket, NULL, NULL );

поток заморозиться, ожидая accept.

Автор: MAxZ 08.11.04, 11:37
гм... а можешь тогда привести новый код?

Автор: Duke Nuken 08.11.04, 12:08
Предлагаю обмен, мой код на код для вставки смайликов (bmp) в Rich Edit.
Задача простая, есть bmp файл, MFC проект. Простое диалоговое окно.
Нажимеш на кнопку и эта bmp записываеться в Rich Edit.
Никак не могу смайлы добавить в проект :)
Сделаеш и код твой.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)