Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2422797
  • 博文数量: 298
  • 博客积分: 7876
  • 博客等级: 准将
  • 技术积分: 5500
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-23 13:39
文章存档

2013年(2)

2012年(142)

2011年(154)

分类: LINUX

2011-04-07 13:51:27

16)多接口设计

 

注:所以文章红色字体代表需要特别注意和有问题还未解决的地方,蓝色字体表示需要注意的地方

 

1.     本文所介绍的程序平台

开发板:arm9-mini2440

虚拟机为:Red Hat Enterprise Linux 5

开发板上系统内核版本:linux-2.6.32.2

 

2.  多接口设计

通常服务器所在的主机存在多个网络接口,即包含多个网络地址。某个特定服务一般采用固定的端口号,而网络地址却由所运行的主机不同而不同,因此如果服务器所在的主机存在多个网络接口,应考虑多地址绑定的问题。

服务器多地址绑定的主要两中情况:

单个服务器绑定到多个接口

多个服务器绑定到不同接口

 

3. 单个服务器绑定到多个接口

服务器的绑定通过bind()函数实现的,为了绑定到多个接口需要使用常量INADDR_ANY来代表本机所以有效地IP地址,当服务器绑定到所有的IP地址后,客户可以从任一地址来获得服务器服务。

例如:

服务器 2个IP地址: 192.9.200.10 和192.9.200.20

TCP服务器绑定到所有地址上并且端口号为80 如下

******************************************************************\

192.9.200.10

192.9.200.20

 

TCP服务器

 

{*.80,*.*}

(监听套接字)

******************************************************************\

 

{*.80,*.*}表示本地套接字所有地址上并且端口号为80,远程套接字为任何地址和任何端口。

当远程客户进行连接请求,建立连接并产生连接套接字后,连接套接字地址为客户请求地址。

 

******************************************************************\

192.9.200.10

192.9.200.20

 

TCP服务器

 

{*.80,*.*}

(监听套接字)

|

| fork()

|

V

                      TCP服务器(子进程)

{192.9.200.10.80,

201.8.220.1.1200}

 

|

| 连接

|

V

201.8.220.1

TCP客户机

{201.8.220.1.1200,

192.9.200.10.80}

 

            

******************************************************************\

 

3.1多线程服务器多接口实例

 

为了获得被连接的IP地址,应该调用getsockname函数,下面程序是一个多线程并发服务器(注意没消除僵死进程),他绑定于所有IP地址并且端口号为1234,当与客户建立连接之后显示被连接的IP地址以及端口号。

注意:为什么必须主机端口号要与客户机端口号一致才能连接??并且显示的端口号又不是客户机上绑定的端口号,地址也不是客户机的地址??

 

 

 #include           /* These are the usual header files */

 #include           /* for bzero() */

 #include          /* for close() */

 #include

 #include

 #include

 #include

#include

 

 #define PORT 1234   /* Port that will be opened */

 #define BACKLOG 2   /* Number of allowed connections */ 

 void process_cli(int connectfd, sockaddr_in client);

 

 main()

 {

 int listenfd, connectfd; /* socket descriptors */

 pid_t pid;

 struct sockaddr_in server; /* server's address information */

 struct sockaddr_in client; /* client's address information */

 socklen_t sin_size;

 

 /* creaet TCP socket  */

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

 {

   /* handle exception */

   perror("Creating socket failed.");

   exit(1);

 }

 

 bzero(&server,sizeof(server));

 server.sin_family=AF_INET;

 server.sin_port=htons(PORT);

 server.sin_addr.s_addr = htonl (INADDR_ANY);

 

 if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {

   /* handle exception */

   perror("Bind error.");

   exit(1);

   }   

 

 if(listen(listenfd,BACKLOG) == -1){  /* calls listen() */

   perror("listen() error\n");

   exit(1);

   }

 

 sin_size=sizeof(struct sockaddr_in);

 while(1)

 {

   /* accept connection */

   if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {

     perror("accept() error\n");

     exit(1);

     }

 

   /*  create child process */

   if ((pid=fork())>0) {

     /* parent process */

     close(connectfd);

     continue;

   }

   else if (pid==0) {

     /* child process */

     close(listenfd);

     process_cli(connectfd, client);

     exit(0);    

   }

   else {

     printf("fork error\n");

     exit(0);

   }

 }

 

 close(listenfd);   /* close listenfd */        

 }

 

 void process_cli(int connectfd, sockaddr_in client)

 {

 sockaddr_in address;

 socklen_t namelen;

 

 getsockname(connectfd,  (sockaddr  *)&address,  &namelen);

 printf("Connected to address ( %s ) port :%d\n  ",inet_ntoa(address.sin_addr),address.sin_port); //注意这里的信息 我不能理解?

 close(connectfd); /*  close connectfd */

 }

 

 

4. 多个服务器绑定到多个接口

一个主机上经常运行多个服务器,有时他们被绑定到不同的接口上用来服务不同的客户。例如:有两个部门分别通过两个接口(192.9.200.10 和192.9.200.20 )访问服务器,这时需要启动两个服务器,一个绑定到192.9.200.10上,另一个绑定到192.9.200.20上。

 

4.1多个服务器绑定到多个接口实例

 

用户通过命令行参数输入该服务器所绑定的地址,服务器完成地址绑定后监听客户连接并为客户服务。

 

注意:在默认的情况下,bind()函数不能绑定两个以上的服务器到相同的端口,否则会产生“bind error: address already in use”,解决办法就是利用套接字选项SO_REUSEADDR,他允许多个服务器绑定到相同端口但是不同地址上。

 

#include           /* These are the usual header files */

 #include           /* for bzero() */

 #include          /* for close() */

 #include

 #include

 #include

 #include

#include

#include

 

 #define PORT 1234   /* Port that will be opened */

 #define BACKLOG 2   /* Number of allowed connections */

 void process_cli(int connectfd, sockaddr_in client);

 

 main(int argc, char* argv[])

 {

 int listenfd, connectfd; /* socket descriptors */

 pid_t pid;

struct hostent *he;

 struct sockaddr_in server; /* server's address information */

 struct sockaddr_in client; /* client's address information */

 socklen_t sin_size;

 

 if (argc !=2) {      

   printf("Usage: %s \n",argv[0]);

   exit(1);

   }

 

 if ((he = gethostbyname(argv[1]))==NULL){ /* calls gethostbyname() */

   printf("gethostbyname() error\n");

   exit(1);

   }

 

 /* Create TCP socket  */

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

 {

   /* handle exception */

   perror("Creating socket failed.");

   exit(1);

   }

 

 bzero(&server,sizeof(server));

 server.sin_family=AF_INET;

 server.sin_port=htons(PORT);

 server.sin_addr = *((struct in_addr *)he->h_addr);

 

 int opt = SO_REUSEADDR;

 setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,  &opt, sizeof(opt));

 

 if (bind(listenfd, (struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {

   /* handle exception */

   perror("Bind error.");

   exit(1);

   }   

 

 if(listen(listenfd,BACKLOG) == -1){  /* calls listen() */

   perror("listen() error\n");

   exit(1);

   }

 

 sin_size=sizeof(struct sockaddr_in);

 while(1)

 {

 /* accept  connection */

 if ((connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size))==-1) {

   perror("accept() error\n");

   exit(1);

   }

 

 /*  create child process */

 if ((pid=fork())>0) {

   /* parent process */

   close(connectfd);

   continue;

   }

 else if (pid==0) {

   /* child process */

   close(listenfd);

   process_cli(connectfd, client);

   exit(0);    

   }

 else {

   printf("fork error\n");

   exit(0);

   }

 }

 close(listenfd);   /* close listenfd */        

 }

 

 void process_cli(int connectfd, sockaddr_in client)

 {

 sockaddr_in address;

 socklen_t namelen;

 

 getsockname(connectfd,  (sockaddr  *)&address,  &namelen);

 printf("Connected to address ( %s )\n  ",inet_ntoa(address.sin_addr) );

 close(connectfd); /*  close connectfd */

 }

 

附加内容:Linux系统在线增加多个ip

阅读(1117) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~