Chinaunix首页 | 论坛 | 博客
  • 博客访问: 535184
  • 博文数量: 181
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1498
  • 用 户 组: 普通用户
  • 注册时间: 2013-12-22 15:17
个人简介

用发呆的时间来理清自己的思绪

文章存档

2015年(7)

2014年(134)

2013年(40)

分类: 嵌入式

2014-10-27 23:32:24

服务器端代码实现:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>
  4. #include <sys/socket.h>
  5. #include <netinet/in.h>
  6. #include <arpa/inet.h>

  7. //信号的处理非常类似于中断的处理,当有信号产生时,执行这个函数
  8. void handler_signal(int signum)
  9. {
  10.     //非阻塞方式调用,有子进程退出时,对子进程进行收尸
  11.     waitpid(-1,NULL,WNOHANG);
  12.     return ;
  13. }

  14. int do_client(int connect_fd)
  15. {
  16.     int n;
  17.     char buf[1024];
  18.     
  19.     while(1)
  20.     {
  21.         n = read(connect_fd,buf,sizeof(buf) - 1);
  22.         if(n <= 0)
  23.             break;

  24.         buf[n] = '\0';
  25.         printf("Read %d bytes : %s\n",n,buf);
  26.     
  27.         if(strncmp(buf,"quit",4)==0)
  28.             break;
  29.     }

  30.     //子进程直接退出,让父进程对其收尸
  31.     exit(EXIT_SUCCESS);
  32. }

  33. //./server ip port
  34. int main(int argc, const char *argv[])
  35. {
  36.     int pid;
  37.     int sockfd;
  38.     int connect_fd;
  39.     struct sockaddr_in server_addr;
  40.     struct sockaddr_in peer_addr;
  41.     socklen_t addrlen = sizeof(struct sockaddr);

  42.     if(argc < 3)
  43.     {
  44.         fprintf(stderr,"Usage : %s \n",argv[0]);
  45.         exit(EXIT_FAILURE);
  46.     }

  47.     //为了防止将尸态子进程的出现,子进程退出时,父进程需要对子进程收尸
  48.     //设置SIGCHLD信号处理方式:捕捉
  49.     if(signal(SIGCHLD,handler_signal) == SIG_ERR)
  50.     {
  51.         perror("Fail to signal");
  52.         exit(EXIT_FAILURE);
  53.     }

  54.     //1.创建流式套接字
  55.     sockfd = socket(AF_INET,SOCK_STREAM,0);
  56.     if(sockfd < 0){
  57.         perror("Fail to socket");
  58.         exit(EXIT_FAILURE);
  59.     }

  60.     //2.填充服务器的IP地址和端口信息
  61.     server_addr.sin_family = AF_INET;
  62.     server_addr.sin_port = htons(atoi(argv[2]));
  63.     server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  64.     //3.把服务器的端口和IP地址信息和流式套接字绑定
  65.     if(bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
  66.     {
  67.         perror("Fail to bind");
  68.         exit(EXIT_FAILURE);
  69.     }

  70.     //4.设置流式套接字为监听模式
  71.     //在服务器端的某个应用程序需要一种状态去等候客户端的通信邀请,这种状态称之
  72.     //为“监听”,监听本身不具备连接的功能,它仅仅是一种等候。
  73.     listen(sockfd,128);

  74.     printf("listen ...\n");

  75.     while(1)
  76.     {
  77.         //在请求队列中提取客户端的请求,提取成功之后会新创建一个新客户端的套接字,
  78.         //这个新的套接字才是和客户端真正进行通信的套接字,而前面的套接字是用于实
  79.         //现监听的。
  80.         connect_fd = accept(sockfd,(struct sockaddr *)&peer_addr,&addrlen);
  81.         if(connect_fd < 0){
  82.             perror("Fail to accept");
  83.             exit(EXIT_FAILURE);
  84.         }

  85.         printf("connect_fd : %d\n",connect_fd);

  86.         printf("-----------------------------\n");
  87.         printf("Port : %d\n",ntohs(peer_addr.sin_port));
  88.         printf("Ip : %s\n",inet_ntoa(peer_addr.sin_addr));
  89.         printf("-----------------------------\n");

  90.         pid = fork();
  91.         if(pid < 0){
  92.             perror("Fail to fork");
  93.             exit(EXIT_FAILURE);
  94.         }

  95.         if(pid == 0)
  96.         {
  97.             //子进程中读取客户端的发送的数据,并且把父进程中拷贝过来的监听的套接字关闭
  98.             close(sockfd);
  99.             do_client(connect_fd);
  100.         }
  101.     
  102.         //为了防止文件描述符浪费,父子进程在最后执行完之后都应该关闭已经打开的文件描述符
  103.         close(connect_fd);
  104.     }
  105.     
  106.     return 0;
  107. }
客户端代码实现:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>

  6. //./server ip port
  7. int main(int argc, const char *argv[])
  8. {
  9.     int n;
  10.     int sockfd;
  11.     int connect_fd;
  12.     char buf[1024];
  13.     struct sockaddr_in server_addr;
  14.     struct sockaddr_in peer_addr;
  15.     socklen_t addrlen = sizeof(struct sockaddr);

  16.     if(argc < 3)
  17.     {
  18.         fprintf(stderr,"Usage : %s \n",argv[0]);
  19.         exit(EXIT_FAILURE);
  20.     }

  21.     //1.创建流式套接字
  22.     sockfd = socket(AF_INET,SOCK_STREAM,0);
  23.     if(sockfd < 0){
  24.         perror("Fail to socket");
  25.         exit(EXIT_FAILURE);
  26.     }

  27.     //2.填充服务器IP地址和端口信息
  28.     server_addr.sin_family = AF_INET;
  29.     server_addr.sin_port = htons(atoi(argv[2]));
  30.     server_addr.sin_addr.s_addr = inet_addr(argv[1]);
  31.     //3.链接服务器(实质上是完成3次握手,链接成功之后Linux内核会把请求放置在内核的请求队列中)
  32.     // 特别注意:这个函数仅仅只在客户端使用,主要的目的就是完成和服务器的3次握手
  33.     if(connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0)
  34.     {
  35.         perror("Fail to connect");
  36.         exit(EXIT_FAILURE);
  37.     }

  38.     while(1)
  39.     {
  40.         printf("client >");
  41.         fgets(buf,sizeof(buf),stdin);
  42.         buf[strlen(buf) - 1] = '\0';

  43.         //给服务器发送数据
  44.         n = write(sockfd,buf,strlen(buf));
  45.         if(n < 0){
  46.             perror("Fail to write");
  47.             exit(EXIT_FAILURE);
  48.         }
  49.     }
  50.     
  51.     return 0;
  52. }
运行测试结果如下:

点击(此处)折叠或打开

  1. ubuntu@ubuntu:~/network_teacher/day02/tcp/server$ ./server 192.168.127.131 8888
  2. listen ...
  3. connect_fd : 4
  4. -----------------------------
  5. Port : 53984
  6. Ip : 192.168.127.131
  7. -----------------------------
  8. Read 6 bytes : hello
  9. Read 5 bytes : world
  10. Read 3 bytes : xxx

点击(此处)折叠或打开

  1. ubuntu@ubuntu:~/network_teacher/day02/tcp/client$ ./client 192.168.127.131 8888
  2. client >hello
  3. client >world
  4. client >xxx
  5. client >
阅读(947) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~