Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129124
  • 博文数量: 19
  • 博客积分: 508
  • 博客等级: 下士
  • 技术积分: 306
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-11 21:04
文章分类

全部博文(19)

文章存档

2011年(16)

2009年(3)

我的朋友

分类: LINUX

2011-08-07 20:57:36

Outline 

    - 1.数据结构

    - 2.服务器端编程框架

    - 3.客户端编程框架

    - 4.服务器端select多路IO转接使用框架    ======================================================================================

1.数据结构
struct addrinfo;
该结构的主要用途是使用getaddrinfo函数,自动填充socket相关信息。
 
struct sockaddr;
struct sockaddr_storage;
这两个为通用的socket结构,sockaddr可以指向sockaddr_in和sockaddr_in6,sockaddr_storage的大小可以容纳下任何一种socket(IPv4, IPv6, etc)。
 
struct sockaddr_in;
struct sockaddr_in6;
分别对应IPv4和IPv6地址。
 
2. 服务器端编程框架
getaddrinfo()
socket()
bind()
freeaddrinfo()
listen()
new_fd = accept()
fork() (为避免僵尸进程,可以使用信号SIGCHLD或者fork两次的方法)
recv(new_fd, ...)/send(new_fd, ...)
 
3. 客户端编程框架
getaddrinfo()
socket()
connect() (可选,SOCK_STREAM/SOCK_DGRAM)
freeaddrinfo()
recv()/recvfrom()/send()/sendto()
 
4. 服务器端select多路IO转接使用框架
a broadcast-echo server
测试方法:
打开多个
telnet localhost 8888
在某个客户端中发送消息后,其他客户端会收到消息回显
  1. /*
  2.  * =====================================================================================
  3.  *
  4.  * Filename: multichat_server.c
  5.  *
  6.  * Description:
  7.  *
  8.  * Version: 1.0
  9.  * Created: 08/07/11 15:05:34
  10.  * Revision: none
  11.  * Compiler: gcc
  12.  *
  13.  * Author: YOUR NAME (),
  14.  * Company:
  15.  *
  16.  * =====================================================================================
  17.  */
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <sys/socket.h>
  21. #include <netdb.h>
  22. #include <sys/select.h>
  23. #include <string.h>
  24. #include <unistd.h>
  25. #include <arpa/inet.h>

  26. int main(int argc, char *argv[])
  27. {
  28.     struct addrinfo hints, *addr;
  29.     struct sockaddr_storage client_addr;    
  30.     int ret;
  31.     int fd, new_fd;
  32.     fd_set cons, read_fds;
  33.     int max_fd;
  34.     char buf[50];
  35.     char addrbuf[INET_ADDRSTRLEN];
  36.     int i, j;
  37.     int addrlen;
  38.     int yes = 1;
  39.     int nbytes;

  40.     memset(&hints, 0, sizeof(struct addrinfo));
  41.     hints.ai_flags = AI_PASSIVE;
  42.     hints.ai_family = AF_INET;
  43.     hints.ai_socktype = SOCK_STREAM;

  44.     ret = getaddrinfo(NULL, "8888", &hints, &addr);
  45.     if (ret != 0) {
  46.         printf("getaddrinfo error: %s\n", gai_strerror(ret));
  47.         return -1;
  48.     }
  49.     
  50.     while(addr != NULL){
  51.         fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
  52.         if (fd < 0) {
  53.             perror("open socket error");
  54.             return -1;
  55.         }
  56.         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  57.         ret = bind(fd, (struct sockaddr *)addr->ai_addr, addr->ai_addrlen);
  58.         if (ret < 0) {
  59.             perror("bind error");
  60.             close(fd);
  61.             addr = addr->ai_next;
  62.             continue;
  63.         }
  64.         
  65.         break;
  66.     }

  67.     ret = listen(fd, 10);
  68.     if (ret < 0) {
  69.         perror("listen error");
  70.         close(fd);
  71.         return -1;
  72.     }
  73.     
  74.     FD_ZERO(&cons);
  75.     FD_SET(fd, &cons);
  76.     max_fd = fd;
  77.     
  78.     while(1){
  79.         read_fds = cons;

  80.         ret = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
  81.         if (ret < 0) {
  82.             perror("select error");
  83.             return -1;
  84.         }
  85.         
  86.         for (i = 0; i <= max_fd; i++) {
  87.             ret = FD_ISSET(i, &read_fds);
  88.             if (ret == 1) {
  89.                 if (i == fd) {
  90.                     //we've got a new connection
  91.                     addrlen = sizeof(struct sockaddr_in);
  92.                     new_fd = accept(i, (struct sockaddr *)&client_addr, &addrlen);
  93.                     if (new_fd < 0) {
  94.                         perror("accept error");
  95.                     }

  96.                     printf("new connection from %s\n",
  97.                             inet_ntop(client_addr.ss_family, &((struct sockaddr_in *)&client_addr)->sin_addr, addrbuf, INET6_ADDRSTRLEN));

  98.                     FD_SET(new_fd, &cons);
  99.                     if (new_fd > max_fd)
  100.                         max_fd = new_fd;
  101.                 } else {
  102.                     //client socket is readable
  103.                     nbytes = recv(i, buf, sizeof(buf), 0);
  104.                     
  105.                     //the connection is closed
  106.                     if (nbytes == 0) {
  107.                         close(i);
  108.                         FD_CLR(i, &cons);
  109.                     }
  110.                     else if (nbytes > 0) { //data available on i
  111.                         for (j = 0; j <= max_fd; j++) {
  112.                             ret = FD_ISSET(j, &cons);
  113.                             if (ret == 0 || j == fd || j == i)
  114.                                 continue;

  115.                             nbytes = send(j, buf, nbytes, 0);
  116.                             if (nbytes < 0)
  117.                                 perror("server echo error");
  118.                         }
  119.                     }
  120.                 }
  121.             }
  122.         }
  123.     }

  124.     return 0;
  125. }
 
阅读(4806) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~