nonblocking sockets C (си)

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by iSlava, 7 Feb 2010.

  1. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    доброго времени суток, уважаемые.
    писал программку на Си - что то отдалённо напоминающее хттп клиент
    отправляет гет запрос и ждет ответа сервера.
    использует сокеты.
    Code:
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h> 
    
    void error(char *msg)
    {
        perror(msg);
        exit(0);
    }
    
    int main(int argc, char *argv[])
    {
        int sockfd, portno, n;
        char str[] = "GET http://127.0.0.1:8088/?identifier=1z2y3z HTTP/1.0\r\n\r\n";
        struct sockaddr_in serv_addr;
        struct hostent *server;
    
        char buffer[256];
        if (argc < 3) {
           fprintf(stderr,"usage %s hostname port\n", argv[0]);
           exit(0);
        }
        portno = atoi(argv[2]);
        sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) 
            error("ERROR opening socket");
        server = gethostbyname(argv[1]);
        if (server == NULL) {
            fprintf(stderr,"ERROR, no such host\n");
            exit(0);
        }
        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        bcopy((char *)server->h_addr, 
             (char *)&serv_addr.sin_addr.s_addr,
             server->h_length);
        serv_addr.sin_port = htons(portno);
        if (connect(sockfd,&serv_addr,sizeof(serv_addr)) < 0) 
            error("ERROR connecting");
          bzero(buffer,256);
         n = write(sockfd,str,strlen(str));
        if (n < 0) 
             error("ERROR writing to socket");
        bzero(buffer,256);
        n = read(sockfd,buffer,255);
        if (n < 0) 
             error("ERROR reading from socket");
        printf("%s\n",buffer);
        return 0;
    }
    хочу переделать функционал так, чтобы не обрывая соединение, в буфер/переменную (нужное подчеркнуть) попадал ответ сервера.
    делается это с помощью non-blocking sockets
    применить наверное к этому
    Code:
     n = read(sockfd,buffer,255);
    след решение выдает ошибку
    Code:
    #include <unistd.h>
    #include <fcntl.h>
    .
    .
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(sockfd, F_SETFL, O_NONBLOCK);
    n = read(sockfd,buffer,255);
    .
    .
    ERROR reading from socket: Transport endpoint is not connected

    Вот тут всё расписано, но у меня не получается сделать нон блокинг сокетс.
    Если кто сможет переписать программку из листинга 7 из C++ в C буду благодарен.
    Прошу помощи
    P.S. сейчас у меня линукс установлен, но юзать прожку буду на мастдае. что то мне думается что на нём работать это не будет и надо использовать winsock api :confused:
     
  2. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    думаешь правильно....
    в мастдае свои механизмы особенно что касается выставление обработчиков
    WSAAsyncSelect...
    вызова ф-ций этих обработчиков!

    есть правда некоторое сходство на блокирующих сокетах!
     
  3. Gar|k

    Gar|k Moderator

    Joined:
    20 Mar 2009
    Messages:
    1,166
    Likes Received:
    266
    Reputations:
    82
    на блокирующих сокетах тоже можно жить... надо лишь знать что такое потоки и евенты... createThread, createEvent
     
    _________________________
  4. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    переписал на winsock с неблокирующими сокетами.
    доп зависимости в линкере wsock32.lib Ws2_32.lib
    Code:
    #include <stdio.h>      /* for printf(), fprintf() */
    #include <winsock.h>    /* for socket(),... */
    #include <stdlib.h>     /* for exit() */
    
    #define RCVBUFSIZE 32   /* Size of receive buffer */
    
    void DieWithError(char *errorMessage){
        perror(errorMessage);
        exit(0);
    };  /* Error handling function */
    
    void main(int argc, char *argv[])
    {
        int sock;                        /* Socket descriptor */
        struct sockaddr_in echoServAddr; /* Echo server address */
        unsigned short echoServPort;     /* Echo server port */
        char *servIP;                    /* Server IP address (dotted quad) */
        
        char echoString[]= "GET http://127.0.0.1:8088/?identifier=1z2y3z HTTP/1.0\r\n\r\n";
        char echoBuffer[RCVBUFSIZE];     /* Buffer for echo string */
        int echoStringLen;               /* Length of string to echo */
        int bytesRcvd, totalBytesRcvd;   /* Bytes read in single recv() and total bytes read */
        WSADATA wsaData;                 /* Structure for WinSock setup communication */
        unsigned long nonblocking = 1;
        if ((argc < 2) || (argc > 3))    /* Test for correct number of arguments */
        {
            fprintf(stderr, "Usage: %s <Server IP> <Echo Port>\n", argv[0]);
            exit(1);
        }
    
        servIP = argv[1];             /* First arg: server IP address (dotted quad) */
      echoServPort = argv[2];         /* Second arg: server port */
    
       
        if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) /* Load Winsock 2.0 DLL */
        {
            fprintf(stderr, "WSAStartup() failed");
            exit(1);
        }
    
        /* Create a reliable, stream socket using TCP */
        if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
            DieWithError("socket() failed");
    
        /* Set the socket to nonblocking */
        if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0)
            DieWithError("ioctlsocket() failed");
    
        /* Construct the server address structure */
        memset(&echoServAddr, 0, sizeof(echoServAddr));     /* Zero out structure */
        echoServAddr.sin_family      = AF_INET;             /* Internet address family */
        echoServAddr.sin_addr.s_addr = inet_addr(servIP);   /* Server IP address */
        echoServAddr.sin_port        = htons(echoServPort); /* Server port */
        /* Establish the connection to the echo server */
        if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
            DieWithError("connect() failed");
    
        echoStringLen = strlen(echoString);          /* Determine input length */
    
        /* Send the string, including the null terminator, to the server */
        if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
            DieWithError("send() sent a different number of bytes than expected");
    
        /* Receive the same string back from the server */
        totalBytesRcvd = 0;
        printf("Received: ");                /* Setup to print the echoed string */
        while (totalBytesRcvd < echoStringLen)
        {
            /* Receive up to the buffer size (minus 1 to leave space for 
               a null terminator) bytes from the sender */
            if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
                DieWithError("recv() failed or connection closed prematurely");
            totalBytesRcvd += bytesRcvd;   /* Keep tally of total bytes */
            echoBuffer[bytesRcvd] = '\0';  /* Add \0 so printf knows where to stop */
            printf("%s", echoBuffer);            /* Print the echo buffer */
        }
    
        printf("\n");    /* Print a final linefeed */
    
        closesocket(sock);
        WSACleanup();  /* Cleanup Winsock */
    
        exit(0);
    }
    при коннекте "program.exe host port"
    ошибка соединения, почему не понимаю :confused:
    connect () failed: no error
     
    #4 iSlava, 7 Feb 2010
    Last edited: 7 Feb 2010
  5. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    ты не понял!!! В Виндоузе неблокирующие сокеты реализуются через
    WSA**** функции

    и самую главную из них я указывал

    твоей программе приходят события FD_READ FD_ACCEPT FD_CLOSE ( FD_WRITE FD_CONNECT )
    а обработчики быстро обрабатывают!

    ... но по моему плохая это идея линуксоиду писать под мастдай на неблокирующих!
    В этом случае ты должен понимать событийную модель мастдая!
     
    #5 Retimiled, 7 Feb 2010
    Last edited: 7 Feb 2010
  6. Kaimi

    Kaimi Well-Known Member

    Joined:
    23 Aug 2007
    Messages:
    1,732
    Likes Received:
    809
    Reputations:
    231
    Да ладно?

    http://msdn.microsoft.com/en-us/library/ms738573%28VS.85%29.aspx
     
    _________________________
  7. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    ну проблема то не в этом) неблокирующие я правильно реализовал, смотри :)
    Хотя и WSAIoctl тоже хорош, помощнее будет
    сейчас буду мучать события
     
  8. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    2 Kaimi
    пости по теме, бросать топики близкие по теме ГЛУПО , то у ТС гораздо ближе к истине чум тупые ссылки на МСДН ! У всех есть МСДН посмотрят и без тебя!

    TC
    неблокирующие сокеты отдают управление сразу, например recv вернет сразу с нулевым результатом , но гонять recv в цикле ГЛУПО если recv не ждет принятия пакета..... задерживать слипами так же ГЛУПО ... в этом случае проигрыш в производительности блокирующему! Поэтому сервера пишут на асинхронных сокетах учитывающих событийную моlель мастдая,тогда я вполне конкурирую с реализацией в других ОС!

    Пишу лет 10-ть на асинхронных 8))
     
    #8 Retimiled, 7 Feb 2010
    Last edited: 7 Feb 2010
  9. Kaimi

    Kaimi Well-Known Member

    Joined:
    23 Aug 2007
    Messages:
    1,732
    Likes Received:
    809
    Reputations:
    231
    Ты вообще умеешь формулировать свои высказывания более менее упорядоченно? Или у тебя психическое расстройство и на базе него проблемы со знаками препинания и ходом мыслей?
     
    _________________________
  10. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    Модератор потрите флуд Kaimi

    Kaimi зачем ты ходишь и засираешь темы?
     
  11. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    TC как ты будешь реализовывать логику обмена?
    реализация твоя проста.... но логику посложнее ты не сможешь реализовать
    либо скатишься к СЛИПАМ о которых я писал ВЫШЕ!

    промоделируй

    server--------------------------------client
    1 пакет >>>>>>>>>>>>>>
    <<<<<<<<<<<<<<<<<<<< 2 пакет
    <<<<<<<<<<<<<<<<<<<< 3 пакет
    4 пакет >>>>>>>>>>>>>>

    детское программирование обычно сводится
    принял
    послал
    принял
    послал
    etc

    но это первый уровень! :D
     
    #11 Retimiled, 7 Feb 2010
    Last edited: 7 Feb 2010
  12. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    я нашел на мсдн'е полный клиент winsock
    http://msdn.microsoft.com/en-us/library/ms737591(VS.85).aspx
    сейчас разбираю, буду тестить. Он вроде неблокирующий
    только не компилится, куча ошибок, хотя в проекте включаю Ws2_32.lib, Mswsock.lib, и Advapi32.lib
     
    #12 iSlava, 7 Feb 2010
    Last edited: 7 Feb 2010
  13. Retimiled

    Retimiled Banned

    Joined:
    23 Dec 2009
    Messages:
    110
    Likes Received:
    17
    Reputations:
    0
    Высоконагрузочный для ПРОЦА код годен только для примера!
    представь скорость с которой будет крутиться последний цикл на recv 8)))))))))))))))

    то что он заблокирует основную нитку допустим диалогового окна это просто цветочки!

    ... и будешь сидеть и думать какой нефиговый НЕБЛОКИРУЮЩИЙ сокет 8))

    лана не буду больше писать!
     
    #13 Retimiled, 7 Feb 2010
    Last edited: 7 Feb 2010
  14. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    а он ведь на Си? или на cpp?
    Retimiled, может сможешь поправить мой код ? а то я не профи в ентом деле
     
    #14 iSlava, 7 Feb 2010
    Last edited: 7 Feb 2010
  15. iSlava

    iSlava New Member

    Joined:
    24 Aug 2009
    Messages:
    72
    Likes Received:
    4
    Reputations:
    0
    проблема решена, код переписан
     
    #15 iSlava, 7 Feb 2010
    Last edited: 8 Feb 2010