- 论坛徽章:
- 0
|
本帖最后由 lz_fine 于 2011-11-03 09:36 编辑
我用glib库实现了一个socket的接收程序,流程是这样的,先是初始化一个socket:sfd然后对sfd进行listen,然后得到sfd的iochannel,接着对它的输入进行监视,用g_io_add_watch,回调函数是callback,如果有客户端进行了连接,会调用callback,callback里会根据传递进来的iochannel得到sfd,然后进行accept,再对新得到的connfd的输入进行监视,回调函数是callback1,同时增加一个超时回调函数,回调函数是timeoutCallback,如果这个客户端有数据传入,那么会调用callback1,这个函数中会用g_io_channel_read_chars读取传入的数据,如果接受到eof,或者超时,那么会关闭连接,回收资源,对应的函数是freeTerminalData,这个函数内会用g_source_remove remove接受source和超时source,close连接的fd,g_io_channel_shutdown shutdown对应的iochannel,最后再对iochannel进行g_io_channel_unref
现在有几个疑问:
1.这样的流程对不对,是否有什么问题
2.我看到一篇文章上说不能在回调函数中shutdown iochannel,请问这样说对不对,为什么
原文网址:http://blog.chinaunix.net/space.php?uid=796091&do=blog&id=2035372
3.g_io_channel_read_chars这个如果每次读一个字节,需要读的次数太多了,如果读很多字节的话没有读到这么多字节前这个函数会阻塞不会返回,请问怎么做才能像recv那样一次把所有缓冲区的数据都读出来
4.还有glib库上有一个结构体GIOFuncs,包含有很多函数指针,如io_read,io_write,io_seek,io_close,io_create_watch等等,请问这个应该怎么用,在什么地方用,同样对应于timeout,有一个结构体GSourceFuncs包含有很多函数指针,如prepare,check,dispatch,finalize这个应该怎么用呢?
5.g_io_channel_ref和g_io_channel_unref应该怎么用- #include <glib.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netdb.h>
- #include <unistd.h>
- #define SERVER_PORT "30001"
- #define BUF_SIZE 1024
- #define TIME_OUT_SECONDS (5)
- GMainLoop * loop;
- struct channelfd_s
- {
- GIOChannel * channel;
- gint fd;
- gint timeout;
- guint recvSourceId;
- guint timeoutSourceId;
- };
- //struct channelfd_s globalchannelfd[10];
- /*
- 终端需要关闭时释放相关的资源
- */
- static void freeTerminalData(struct channelfd_s * newTerminal)
- {
- printf("%s:%p\n", __func__, newTerminal);
- g_source_remove(newTerminal->recvSourceId);
- g_source_remove(newTerminal->timeoutSourceId);
- close(newTerminal->fd);
- g_io_channel_shutdown(newTerminal->channel, TRUE, NULL);
- g_io_channel_unref(newTerminal->channel);
- }
- /*
- 用来收发数据的socket fd的超时回调函数
- 超时后关闭连接
- */
- gboolean timeoutCallback(gpointer data)
- {
- struct channelfd_s * newTerminal;
-
- newTerminal = (struct channelfd_s *)data;
-
- newTerminal->timeout++;
- printf("timeout:%d\n", newTerminal->timeout);
- if(newTerminal->timeout > TIME_OUT_SECONDS){
- freeTerminalData(newTerminal);
- return FALSE;
- }
-
- return TRUE;
- }
- /*
- 用来收发数据的socket fd的接收回调函数
- */
- gboolean callback1(GIOChannel * source, GIOCondition condition, gpointer data)
- {
- int retInt;
- char buf[BUF_SIZE];
- gsize bytes_read;
- GIOStatus gIoStatus;
- gsize offset = 0;
- gboolean breakFlag = FALSE;
- struct channelfd_s * newTerminal;
-
- newTerminal = (struct channelfd_s *)data;
-
- while(1)
- {
- gIoStatus = g_io_channel_read_chars(source, buf + offset, 1, &bytes_read, NULL);
- offset++;
- switch (gIoStatus)
- {
- case G_IO_STATUS_ERROR:
- //出错,关闭连接
- printf("recv error\n");
- breakFlag = TRUE;
- freeTerminalData(newTerminal);
- break;
- case G_IO_STATUS_NORMAL:
- //正常,存储到数据区
- printf("recv normal\n");
- if(buf[offset - 1] == '\0'){
- printf("recv:%s\n", buf);
- breakFlag = TRUE;
- }
- break;
- case G_IO_STATUS_EOF:
- //结束,关闭连接
- printf("recv eof\n");
- freeTerminalData(newTerminal);
- breakFlag = TRUE;
- break;
- case G_IO_STATUS_AGAIN:
- //重试,什么都不做
- printf("recv again\n");
- break;
- default:
- break;
- }
- if(breakFlag == TRUE)
- break;
- }
- printf("exit func:%s\n", __func__);
- return TRUE;
- }
- /*
- sfd的回调函数
- 如果该函数被调用,说明有新的socket接入
- */
- gboolean callback(GIOChannel * source, GIOCondition condition, gpointer data)
- {
- struct sockaddr addr;
- socklen_t addrlen = sizeof(struct sockaddr);
- struct channelfd_s * newTerminal;
-
- int listenfd;
- int connfd;
-
- //得到用来listen的fd
- listenfd = g_io_channel_unix_get_fd(source);
-
- //accept新的socket fd
- connfd = accept(listenfd, &addr, &addrlen);
- if(connfd <= 0){
- perror("accept");
- return FALSE;
- }
- printf("accept success:%d\n", connfd);
-
- //初始化一个channelfd结构
- newTerminal = g_new(struct channelfd_s, 1);
- //超时时间初始化为0
- newTerminal->timeout = 0;
-
- newTerminal->fd = connfd;
- newTerminal->channel = g_io_channel_unix_new(connfd);
- //设置iochannel的编码为NULL
- g_io_channel_set_encoding(newTerminal->channel, NULL, NULL);
-
- //增加对新的socket fd的监视
- newTerminal->recvSourceId = g_io_add_watch(newTerminal->channel, G_IO_IN, callback1, newTerminal);
- //增加对新的socket fd超时的监视
- newTerminal->timeoutSourceId = g_timeout_add_seconds(1, timeoutCallback, newTerminal);
-
- return TRUE;
- }
- int main(void)
- {
- /*
- socket init
- */
- struct addrinfo hints;
- struct addrinfo *res, *rp;
- int retInt;
- int reuse;
- int sfd;
- int cfd;
- //get socket address information
- memset(&hints, 0, sizeof(hints));
- hints.ai_flags = AI_PASSIVE;
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = 0;
- hints.ai_canonname = NULL;
- hints.ai_addr = NULL;
- hints.ai_next = NULL;
- retInt = getaddrinfo(NULL, SERVER_PORT, &hints, &res);
- if(retInt != 0)
- {
- printf("getaddrinfo:%s\n", gai_strerror(retInt));
- return -1;
- }
- //get socket & bind
- for (rp = res; rp != NULL; rp = rp->ai_next)
- {
- sfd = socket(rp->ai_family, rp->ai_socktype,
- rp->ai_protocol);
- if (sfd < 0)
- continue;
- //set socket fd reuse
- reuse = 1;
- retInt = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse,
- sizeof(reuse));
- if (retInt < 0)
- {
- perror("setsockopt");
- return -2;
- }
- if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
- break;
-
- close(sfd);
- }
- printf("sfd:%d\n", sfd);
- if (rp == NULL)
- {
- printf("could not bind\n");
- return -3;
- }
- printf("bind success\n");
- freeaddrinfo(res);
- //listen
- retInt = listen(sfd, 10);
- if (retInt < 0)
- {
- perror("listen");
- return -4;
- }
- printf("listen success\n");
-
- GIOChannel * channel;
-
- g_thread_init(NULL);
-
- //生产iochannel
- channel = g_io_channel_unix_new(sfd);
- //设置iochannel的编码为NULL
- g_io_channel_set_encoding(channel, NULL, NULL);
- //对sfd的iochannel监视
- g_io_add_watch(channel, G_IO_IN, callback, NULL);
- loop = g_main_loop_new(NULL, FALSE);
- g_main_loop_run(loop);
-
- return 0;
- }
复制代码 |
|