隐藏的歌手boa:TCP服务器

来源:百度文库 编辑:九乡新闻网 时间:2024/07/07 13:37:59

弄了这么长时间,终于把TCP服务器做好了。现在把它总结一下。

一、服务器框架

  看了一些文章,有很多种TCP服务器,其中并发服务器和多路复用I/O服务器我觉得可用。我们以前的系统用的是并发服务器,它的思想是每一个客户机的请求并不由服务器直接处理,而是服务器创建一个子进程来处理。但是它为了响应客户机的请求,服务器要创建子进程来处理。而创建子进程是一种非常消耗资源的操作,以这弃之不用了。我选择了多路复用I/O服务器模型,这里面主要用到了一个函数fdSelect()。它可以使进程阻塞直至有数据可读入、可写、或超时。

 框架如下:

int fd, max_fd, tmp_fd;

int fd_array[FD_NUM];

int i, rc;

buffer buf[BUF_SIZE];

fd_set read_fd, all_fd;

struct sockaddr_in local;

 

local.sin_family = AF_INET;

local.sin_addr.s_addr = htonl(INADDR_ANY);

local.sin_port  = htons(PORT);

 

if((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)

{

        //error

}

 

if(bind(fd, (struct sockaddr*)&local, sizeof(local)) == -1)

{

        //error

}

 

if(listen(fd, MAX_CONNECTION) == -1)

{

        //error

}

 

memset(fd_array, -1, FD_NUM);

fd_array[0] = fd;

 

FD_ZERO(&all_fd);

FD_SET(fd, &all_fd);

max_fd = fd;

 

while(1)

{

        read_fd = all_fd;

        if(select(max_fd + 1, &read_fd, NULL, NULL, NULL) == -1)

        {

                continue;

        }

 

        if(FD_ISSET(fd, &readfd))

        {

                if((tmp_fd = accept(fd, NULL, NULL)) == -1)

                {

                        continue;

                }

                else

                {

                        for(i = 0; i < FD_NUM; i++)

                        {

                                if(fd_array[i] == -1)

                                {

                                        fd_array[i] = tmp_fd;

                                }

                        }

  

                        FD_SET(tmp_fd, &allfd);

                        if(tmp_fd > max_fd)

                        {

                                max_fd = tmp_fd;

                        }

                }

                continue;

        }

 

        for(i = 0; i < FD_NUM; i++)

        {

                if(FD_ISSET(fd_array[i]), &read_fd)

                {

                        rc = recv(fd_array[i], buf, BUF_SIZE, 0);

                        if(rc <= 0)

                        {

                                //error

                        }

                        else

                        {

                                buf[rc] = '\0';

                                //your operation

                        }

                        break;

                }

        }

}

我的图像发送用了另一个任务来完成,在这个任务中可以分别实现TCP和UDP传送。因为TCP传送时要用到服务器连接产生的SOCKET,而UDP要用到连接时获得的客户端地址,所以把这些信息都设成了全局变量。

二、调试时出的几个问题

1、连接数的限定

   原来想的是如何到了限定的数目后怎样不准它建立连接,程序写得很麻烦。后来才想到,可以先建立连接,再进行判断,如果超出,则断开即可。这样的做会出现的问题是在客户端一定要对此做处理,否则板子这儿已经断开了连接,但客户端还显示了连接上。

2、SOCKET在两个任务之间的传递

  TASKSEND任务里,当用TCP传送图像时,需要tsktcpserver任务里生成的连接socket,我原以为把这个做成全局变量后就可以传递了。但实际不行。查了NDK文档后才知道,每个任务都有自己的文件描述符表,所以必须加上描述符共享命令,对描述符进行拷贝。

3、无法支持UDP传送

  TCP传送成功后,不知为什么,UDP的SENDTO一直返回为45号错误。我查了好长时间,最后问题还是出在那个描述符共享命令了。TCP需要描述符共享,但UDP不需要。

4、全局变量的使用

  在调试时,发现TCP发送图像时,不能对多个已经连接的用户进行传送,仔细检查后,发现是全局变量的问题,这个值在另一个线程中被修改,所以造成错误。去掉这个全局变量,问题解决了。

基本上就遇到这3个问题。