select() base server (проблемы с колом)

Модератор: Модераторы разделов

Аватара пользователя
Asgard
Сообщения: 215
Статус: North Valfader

select() base server

Сообщение Asgard »

Есть простенький select() base сервер. Клиент кидает ему ip сайт, контекст которого требуется ему получить, сервер совершает вышеуказанное действо. Но не всё проходит гладко:

Код: Выделить всё

#define MAXIP 16

int g_opt(const char*, char*[], const int);
void get_site(int, char*);

int main(int argc, char* argv[])
{
    int listenfd, connfd, clients[FD_SETSIZE], nready, port, maxfd, i, maxi, sockfd;
    socklen_t clilen;
    struct sockaddr_in servaddr, cliaddr;
    char ip[MAXIP];
    fd_set rset;

    if(argc < 2)
        err_quit("usage: %s -p <port>", argv[0]);

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if((port = g_opt("-p", argv, argc)) < 0)
                 err_quit("usage: %s -p <port>", argv[0]);

    servaddr.sin_port = htons(port);

    Bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr));
    Listen(listenfd, 9);

    maxfd = listenfd;
    maxi = -1;
    memset(&clients, -1, FD_SETSIZE);
    FD_ZERO(&rset);
    FD_SET(listenfd, &rset);

    for(;;) {
        if((nready = select(maxfd + 1, &rset, NULL, NULL, NULL)) < 0)
            err_sys("error in function select()");

        if(FD_ISSET(listenfd, &rset)) {
            clilen = sizeof(cliaddr);
            connfd = Accept(listenfd, (struct sockaddr*)&cliaddr, &clilen);

            for(i = 0; i < FD_SETSIZE; i++)
                if(clients[i] < 0) {
                    clients[i] = connfd;
                    break;
                }

            if(i == FD_SETSIZE)
                err_quit("too many clients");

            FD_SET(connfd, &rset);

            if(connfd > maxfd)
                maxfd = connfd;
            if(i > maxi)
                maxi = i;
        }

        for(i = 0; i <= maxi; i++) {
            if((sockfd = clients[i]) < 0)
                continue;
            printf("ok; sockfd = %d\n", sockfd);
            if(FD_ISSET(sockfd, &rset)) {
                printf("ready\n");
                if(Read(sockfd, ip, MAXIP) == 0) {
                    printf("client's eof\n");
                    close(sockfd);
                    FD_CLR(sockfd, &rset);
                    clients[i] = -1;
                }
                else {
                    printf("ip = %s\n", ip);
                    printf("getting data\n");
                    get_site(sockfd, ip);
                }
                if(--nready <= 0)
                    break;
            }
        }
    }

    exit(0);
}

int g_opt(const char* opt, char* argv[], const int argc)
{
    int i;

    for(i = 1; i < argc; i++)
        if(strcmp(argv[i], opt) == 0 && argv[i + 1] != NULL)
            return atoi(argv[i + 1]);

    return -1;
}

//[b]Нижеуказанный код не хочет работать[/b]
void get_site(int fd, char* ip)
{
    printf("trying...\n");
    char buf[MAXLINE];
    int ffd;
    struct sockaddr_in tmp_addr;
    fd_set tset;

    ffd = Socket(AF_INET, SOCK_STREAM, 0);

    bzero(&tmp_addr, sizeof(tmp_addr));
    tmp_addr.sin_family = AF_INET;
    tmp_addr.sin_port = htons(80);

//[b]Запарывается на этой функции, выдавая 'неизвестную ошибку'[/b]
    if(inet_pton(AF_INET, ip, &tmp_addr.sin_addr) <= 0)
        err_sys("inet_pton() error");

    Connect(ffd, (struct sockaddr*)&tmp_addr, sizeof(tmp_addr));
    sprintf(buf, "GET / HTTP/1.1\nHOST: %s\n\n", ip);
    Write(ffd, buf, strlen(buf));
    memset(buf, '\0', MAXLINE);

    while(Read(ffd, buf, MAXLINE) > 0)
        Write(fd, buf, strlen(buf));

    close(ffd);
}


Самое странное, что аналогичная fork()-версия сервера работает великолепно. Кто-нибудь может скаать в чём проблема
sator arepo tenet opera rotas ;)
------------------------------------------------------------
LJ
Спасибо сказали:
Аватара пользователя
Asgard
Сообщения: 215
Статус: North Valfader

Re: select() base server

Сообщение Asgard »

на свежею голову решился разобраться с проблемой. Сделал вывод, что я тормоз, ибо грешил на сервер в полной уверености, что написал нормальный клиент, а вся соль была именно в нём. Ошибка:

Код: Выделить всё

/*...*/
FD_SET(sockfd, &rset);
FD_SET(STDIN_FILENO, &rset);

if(select(sockfd + 1, &rset, NULL, NULL, NULL) < 0)
err_sys("seletct() error!");

for(;;) {
if(FD_ISSET(sockfd, &rset)) {
/*...*/
}
/*...*/
}

хотя STDIN_FILENO и дескриптор сокета, должны выставлятся и проверяться не кдиножды, а при каждой итерации цикла, т.е.:

Код: Выделить всё

/*...*/
for(;;) {
FD_SET(sockfd, &rset);
FD_SET(STDIN_FILENO, &rset);

if(select(sockfd + 1, &rset, NULL, NULL, NULL) < 0)
err_sys("seletct() error!");
if(FD_ISSET(sockfd, &rset)) {
/*...*/
}
/*...*/
}
sator arepo tenet opera rotas ;)
------------------------------------------------------------
LJ
Спасибо сказали: