чат-сокет + gio_channel не показывает входящий пакет сразу на языке c? - PullRequest
0 голосов
/ 13 марта 2011

люди, пожалуйста, посмотрите следующий код:

#include <gio/gio.h>
#include <sys/socket.h> //socket();
#include <netinet/in.h> //sockaddr_in
#include <arpa/inet.h>

#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#define RECV_SIZE_MODE 1024 // mmmm

    typedef struct _unit_
    {
        gint sockmax;
        fd_set client,client_tmp;
    } _unit;



gboolean network_deal_api(GIOChannel *in,GIOCondition condition, _unit *unit)
{
    struct sockaddr_storage income;

            unit->client_tmp = unit->client;


    gint i;

    //enum client
    gchar ip[INET_ADDRSTRLEN];
    guint port;

    //convert
    gint insock = g_io_channel_unix_get_fd(in);


    //prepare for new income
    socklen_t income_len = sizeof(income);
    gint newsock;

    //something come in
    char buffer_in[RECV_SIZE_MODE] = {0}; 
    gint recv_sizing;

    switch(condition)
    {
        case G_IO_IN:


        for(i=0; i <= unit->sockmax; i++)
        {

          if(FD_ISSET(i,&unit->client_tmp)) //something coming through handler inside client_tmp, we'll see if the socket has suppose to be someone own
          {
              printf("process on socket number : %d\n",i);
                    if(i == insock) // if handler of socket(); then create new accept handler, if these is a handler of accept();, then else which mean 'incoming data'
                    {
                        newsock = accept(insock,(struct sockaddr*)&income, &income_len);
                        if(newsock == -1)
                        {
                            printf("failure once getting new socket\n");
                            return FALSE;
                        }
                        else
                        {
                            FD_SET(newsock, &unit->client);
                            if(newsock > unit->sockmax)
                            {
                                unit->sockmax = newsock;
                            }

                        inet_ntop(income.ss_family,&((struct sockaddr_in*)&income)->sin_addr,ip,INET_ADDRSTRLEN);
                        port = htons(((struct sockaddr_in*)&income)->sin_port);
                        printf("connected to : %s:%d on socket : %d\n",ip,port,newsock);
                        }



                    }
                    else
                    {


                        if(recv_sizing = recv(i,buffer_in,RECV_SIZE_MODE,0) <= 0)
                        {
                            if(recv_sizing == 0)
                            {
                                printf("socket %d hung up\n",i);
                            }
                            if(recv_sizing == -1)
                            {
                                perror("recv");
                            }
                            close(i);
                            FD_CLR(i,&unit->client);
                        }
                        buffer_in[recv_sizing-1] = '\0';
                        printf("data in : %s length : %d\n",buffer_in,strlen(buffer_in));

                    }
            }
        }
        break;

    }
}

int main()
{


    _unit *unit = (_unit*)malloc(sizeof(_unit));

    struct sockaddr_in my; // set my network device info
    gint rootsock;         // handle the root socket

    GIOChannel *in_handle;
    guint in_handle_watching;       // whether the watching event intend to remove

     FD_ZERO(&unit->client); // initiate
     FD_ZERO(&unit->client_tmp);






    //let construct a server

    //socket
    rootsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    //binding
    memset(&my,0,sizeof(my));
    my.sin_addr.s_addr = INADDR_ANY;
    my.sin_family      = AF_INET;
    my.sin_port        = htons(1111);
    bind(rootsock,(struct sockaddr*)&my,sizeof(my));

    //set the queue, let say for commonly situation 10
    listen(rootsock,10);

    FD_SET(rootsock,&unit->client);

    unit->sockmax = rootsock; //so far its this one


     in_handle = g_io_channel_unix_new(rootsock); // handed socket to channel

    in_handle_watching = g_io_add_watch(in_handle,G_IO_IN|G_IO_OUT,(GIOFunc)network_deal_api,unit);

    printf("server listening on : %d\n",ntohs(my.sin_port));
    printf("look forward for any new income connection\n");

    GMainLoop *loop = g_main_loop_new(NULL,FALSE);
    g_main_loop_run(loop);

    free(unit);

    return 0;
    }

и скомпилируйте и запустите:

$ gcc -o multiplechat_gio multiplechat_gio.c `pkg-config --libs --cflags gio-2.0`
$ ./multiplechat_gio 
  server listening on : 1111
  look forward for any new income connection

кто-то телнет в него:

$ telnet localhost 1111
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
tes
aja
deh
^C

и почему серверне показывает пакет (и показывает пакет, когда другие люди подключаются только к серверу)?

$ ./multiplechat_gio 
server listening on : 1111
look forward for any new income connection
process on socket number : 3
connected to : 127.0.0.1:48814 on socket : 4

что тогда не так?кто-нибудь?

Ответы [ 2 ]

2 голосов
/ 13 марта 2011

Боюсь, вы не понимаете, что такое GIO и что делаете, и пытаетесь смешать его с традиционным циклом select().В вашем текущем коде GIO смотрит только на оригинальный дескриптор файла, который вы дали в g_io_add_watch(in_handle,G_IO_IN|G_IO_OUT,(GIOFunc)network_deal_api,unit);.Он не использует fd_set структуры.

Вы должны использовать GIO API, когда принимаете каждое соединение, создавая новый GIOChannel с g_io_channel_unix_new() и добавляя его с помощью g_io_add_watch().

GIO поддерживает набор и выполняет всю грязную работу за вас в своем цикле событий, уведомляя вас, когда GIOChannel выполнит условие, указанное вами в вызове g_io_add_watch().

(Отредактировано, чтобы сделать более понятным)

Также обратите внимание - последний аргумент g_io_add_watch() должен использоваться для хранения данных, относящихся к добавленному IOChannel (вы будете malloc (), когда вы принимаете соединение),Это где вы прикрепляете данные, специфичные для соединения, такие как имя пользователя или предыдущее состояние и т. Д.

0 голосов
/ 13 марта 2011

Я не очень знаком с GIO, но разве вы не должны звонить g_io_add_watch() на вновь accept(2) -эд сокет?

...