linux下c/c++实例之十socket简单应用

转自:http://blog.csdn.net/taiyang1987912/article/details/49738351

一、简介

      通过socket扫描本机打开的tcp端口号,模拟用户名、密码登录服务器的过程、socket文件传输及模仿http服务器。

二、详解

1、Linux下tcp端口扫描

(1)scanport.c:

[html] view plaincopy
  1. // 端口扫描程序,只支持扫描TCP端口  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <unistd.h>  
  6. #include <errno.h>  
  7. #include <pthread.h>  
  8. #include <sys/types.h>  
  9. #include <sys/socket.h>  
  10. #include <netinet/in.h>  
  11. #include <arpa/inet.h>  
  12.   
  13. // 定义一个端口区间信息  
  14. typedef struct _port_segment {  
  15.     struct in_addr       dest_ip;   // 目标IP  
  16.     unsigned short int  min_port;   // 起始端口  
  17.     unsigned short int  max_port;   // 最大端口  
  18. } port_segment;  
  19.   
  20. /*自定义的错误处理函数*/  
  21. void my_err(const char * err_string, int line)  
  22. {  
  23.     fprintf(stderr, "line:%d  ", line);  
  24.     perror(err_string);  
  25.     exit(1);  
  26. }  
  27.   
  28. /*  
  29.  * 描  述:扫描某一IP地址上的某一个端口的函数  
  30.  * 返回值:-1  出错  
  31.  *     0   目标端口未打开  
  32.  *     1   目标端口已打开  
  33.  */  
  34. int do_scan(struct sockaddr_in serv_addr)  
  35. {  
  36.     int     conn_fd;  
  37.     int     ret;  
  38.     // 创建一个TCP套接字  
  39.     conn_fd = socket(AF_INET, SOCK_STREAM,0);  
  40.     if (conn_fd < 0) {  
  41.         my_err("socket", __LINE__);  
  42.     }  
  43.     // 向服务器端发送连接请求  
  44.     if ((ret = connect(conn_fd, (struct sockaddr *)&serv_addr, sizeof (struct sockaddr))) < 0 ) {  
  45.         if (errno == ECONNREFUSED) {    // 目标端口未打开  
  46.             close(conn_fd);  
  47.             return 0;  
  48.         } else {    // 其他错误  
  49.             close(conn_fd);  
  50.             return -1;  
  51.         }  
  52.     } else if (ret == 0){  
  53.         printf("port %d found in %s\n", ntohs(serv_addr.sin_port),  
  54.                inet_ntoa(serv_addr.sin_addr));  
  55.         close(conn_fd);  
  56.         return 1;  
  57.     }  
  58.   
  59.     return -1;  // 实际执行不到这里,只是为了消除编译程序时产生的警告  
  60. }  
  61.   
  62. // 执行扫描的线程,扫描某一区间的端口  
  63. void * scaner(void *arg)  
  64. {  
  65.     unsigned short int  i;  
  66.     struct sockaddr_in  serv_addr;  
  67.     port_segment        portinfo;     // 端口信息  
  68.   
  69.     // 读取端口区间信息  
  70.     memcpy(&portinfo, arg, sizeof(struct _port_segment));  
  71.   
  72.     // 初始化服务器端地址结构  
  73.     memset(&serv_addr, 0, sizeof (struct sockaddr_in));  
  74.     serv_addr.sin_family = AF_INET;  
  75.     serv_addr.sin_addr.s_addr = portinfo.dest_ip.s_addr;  
  76.     //printf("******serv_addr.sin_addr.s_addr=%s\n", serv_addr.sin_addr.s_addr);  
  77.     //printf("*******portinfo.min_port=%d, portinfo.max_port=%d\n", portinfo.min_port, portinfo.max_port);  
  78.     for (i=portinfo.min_port; i<=portinfo.max_port; i++) {  
  79.         serv_addr.sin_port = htons(i);  
  80.         if (do_scan(serv_addr) < 0) {  
  81.             continue;   // 出错则退出进程  
  82.         }  
  83.     }  
  84.     return NULL;  
  85. }  
  86.   
  87. /*  
  88.  * 命令行参数:-m 最大端口, -a 目标主机的IP地址,  -n 最大线程数  
  89.  */  
  90. int main(int argc, char **argv)  
  91. {  
  92.     pthread_t*  thread;         // 指向所有的线程ID  
  93.     int     max_port;       // 最大端口号  
  94.     int     thread_num;     // 最大线程数  
  95.     int     seg_len;        // 端口区间长度  
  96.     struct in_addr dest_ip;         // 目标主机IP  
  97.     int     i;  
  98.   
  99.     // 检查参数个数  
  100.     if (argc != 7) {  
  101.         printf("Usage: [-m] [max_port] [-a] [serv_address] [-n] [thread_number]\n");  
  102.         exit(1);  
  103.     }  
  104.   
  105.     // 解析命令行参数  
  106.     for (i=1; i<argc; i++) {  
  107.         if (strcmp("-m", argv[i]) == 0) {  
  108.             max_port = atoi(argv[i+1]);   // 将字符串转化为对应的整数  
  109.             if (max_port < 0 || max_port >= 65535) {   //65535会导致死循环  
  110.                 printf("Usage:invalid max dest port\n");  
  111.                 exit(1);  
  112.             }  
  113.             continue;  
  114.         }  
  115.   
  116.         if (strcmp("-a", argv[i]) == 0) {  
  117.             if (inet_aton(argv[i+1], &dest_ip) == 0) {  
  118.                 printf("Usage:invalid dest ip address\n");  
  119.                 exit(1);  
  120.             }  
  121.             continue;  
  122.         }  
  123.   
  124.         if (strcmp("-n", argv[i]) == 0) {  
  125.             thread_num = atoi(argv[i+1]);  
  126.             if (thread_num <= 0) {  
  127.                 printf("Usage:invalid thread_number\n");  
  128.                 exit(1);  
  129.             }  
  130.             continue;  
  131.         }  
  132.     }  
  133.     // 如果输入的最大端口号小于线程数,则将线程数设为最大端口号  
  134.     if (max_port < thread_num) {  
  135.         thread_num = max_port;  
  136.     }  
  137.   
  138.     seg_len = max_port / thread_num;  
  139.   
  140.     if ( (max_port%thread_num) != 0 ) {  
  141.         thread_num += 1;  
  142.     }  
  143.     //printf("max_port=%d, seg_len=%d, thread_num = %d\n", max_port, seg_len, thread_num);  
  144.   
  145.     // 分配存储所有线程ID的内存空间  
  146.     thread = (pthread_t*)malloc(thread_num*sizeof(pthread_t));  
  147.   
  148.     // 创建线程,根据最大端口号和线程数分配每个线程扫描的端口区间  
  149.     port_segment *portinfo = (port_segment*)malloc(thread_num * sizeof(port_segment));  
  150.     for (i=0; i<thread_num; i++) {  
  151.         portinfo[i].dest_ip = dest_ip;  
  152.         portinfo[i].min_port = i*seg_len + 1;  
  153.         //printf("portinfo.min_port=%d, seg_len=%d, i = %d\n", portinfo[i].min_port, seg_len, i);  
  154.   
  155.         if (i == thread_num - 1) {  
  156.             portinfo[i].max_port = max_port;  
  157.         } else {  
  158.             portinfo[i].max_port = portinfo[i].min_port + seg_len - 1;  
  159.         }  
  160.         // 创建线程  
  161.         //if (pthread_create(&thread[i], NULL, scaner, (void *)(portinfo + i)) != 0) {  
  162.         if (pthread_create(&thread[i], NULL, scaner, (void *)(&portinfo[i])) != 0) {  
  163.             my_err("pthread_create", __LINE__);  
  164.         }  
  165.     }  
  166.     for (i=0; i<thread_num; i++) {  
  167.         // 主线程等待子线程结束  
  168.         pthread_join(thread[i], NULL);  
  169.     }  
  170.     free(portinfo);  
  171.     return 0;  
  172. }  

(2)编译运行

[html] view plaincopy
  1. gcc -o scanport scanport.c  -lpthread  
  2.  ./scanport -m 65534 -a 127.0.0.1 -n 1  

       可以通过netstat查看网络相关信息,netstat -tnlp或netstat -tnlpc比较打开的tcp端口号。

2、模拟用户名、密码登录

(1)服务器server.c:
[html] view plaincopy
  1. // Client/Server模型的服务器端  
  2. #include <sys/types.h>  
  3. #include <sys/socket.h>  
  4. #include <unistd.h>  
  5. #include <stdio.h>  
  6. #include <string.h>  
  7. #include <netinet/in.h>  
  8. #include <arpa/inet.h>  
  9. #include <errno.h>  
  10. #include <stdlib.h>  
  11.   
  12. #define BUFSIZE 1024  
  13.   
  14. #define SERV_PORT       4507    // 服务器端的端口  
  15. #define LISTENQ         12  // 连接请求队列的最大长度  
  16.   
  17. #define INVALID_USERINFO    'n' // 用户信息无效  
  18. #define VALID_USERINFO      'y' // 用户信息有效  
  19.   
  20. #define USERNAME        0   // 接收到的是用户名  
  21. #define PASSWORD        1   // 接收到的是密码  
  22.   
  23. struct userinfo {   // 保存用户名和密码的结构体  
  24.     char username[32];  
  25.     char password[32];  
  26. };  
  27. struct userinfo users[ ] = {  
  28. {"linux", "unix"},  
  29. {"4507", "4508"},  
  30. {"clh", "clh"},  
  31. {"xl", "xl"},  
  32. {" "," "}       // 以只含一个空格的字符串作为数组的结束标志  
  33. };  
  34. /*自定义的错误处理函数*/  
  35. void my_err(const char * err_string, int line)  
  36. {  
  37.     fprintf(stderr, "line:%d  ", line);  
  38.     perror(err_string);  
  39.     exit(1);  
  40. }  
  41.   
  42. /*  
  43. * 函数名: my_recv  
  44. * 描 述 : 从套接字上读取一次数据(以'\n'为结束标志)  
  45. * 参 数 : conn_fd     -- 从该连接套接字上接收数据  
  46. *     data_buf  -- 读取到的数据保存在此缓冲中  
  47. *     len       -- data_buf所指向的空间长度  
  48. * 返回值: 出错返回-1, 服务器端已关闭连接则返回0, 成功返回读取的字节数  
  49. */  
  50. int my_recv(int conn_fd, char *data_buf, int len)  
  51. {  
  52.     static  char    recv_buf[BUFSIZE];  // 自定义缓冲区,BUFSIZE定义在my_recv.h中  
  53.     static  char    *pread;         // 指向下一次读取数据的位置  
  54.     static  int len_remain = 0;     // 自定义缓冲区中剩余字节数  
  55.     int         i;  
  56.   
  57.     // 如果自定义缓冲区中没有数据,则从套接字读取数据  
  58.     if (len_remain <= 0) {  
  59.         if ((len_remain =recv(conn_fd, recv_buf, sizeof (recv_buf), 0)) < 0) {  
  60.             my_err("recv", __LINE__);  
  61.         } else if (len_remain == 0) {   // 目的计算机端的socket连接关闭  
  62.             return 0;  
  63.         }  
  64.         pread = recv_buf;   // 重新初始化pread指针  
  65.     }  
  66.   
  67.     // 从自定义缓冲区中读取一次数据  
  68.     for (i=0; *pread != '\n'; i++) {  
  69.         if (i > len) {   // 防止指针越界  
  70.             return -1;  
  71.         }  
  72.         data_buf[i] = *pread++;  
  73.         len_remain--;  
  74.     }  
  75.   
  76.     // 去除结束标志  
  77.     len_remain--;  
  78.     pread++;  
  79.   
  80.     return i;   // 读取成功  
  81. }  
  82. // 查找用户名是否存在,存在返回该用户名的下标,不存在则返回-1,出错返回-2  
  83. int find_name(const char *name)  
  84. {  
  85.     int i;  
  86.   
  87.     if (name == NULL) {  
  88.         printf("in find_name, NULL pointer");  
  89.         return -2;  
  90.     }  
  91.     for (i=0; users[i].username[0] != ' ';i++) {  
  92.         if (strncmp(users[i].username, name, strlen(users[i].username)) == 0) {  
  93.             return i;  
  94.         }  
  95.     }  
  96.   
  97.     return -1;  
  98. }  
  99.   
  100. // 发送数据  
  101. void send_data(int conn_fd, const char *string)  
  102. {  
  103.     if (send(conn_fd, string, strlen(string), 0) < 0) {  
  104.         my_err("send", __LINE__);  // my_err函数在my_recv.h中声明  
  105.     }  
  106. }  
  107.   
  108. int main()  
  109. {  
  110.     int         sock_fd, conn_fd;  
  111.     int         optval;  
  112.     int         flag_recv = USERNAME; // 标识接收到的是用户还是密码  
  113.     int         ret;  
  114.     int         name_num;  
  115.     pid_t           pid;  
  116.     socklen_t       cli_len;  
  117.     struct sockaddr_in  cli_addr, serv_addr;  
  118.     char            recv_buf[128];  
  119.   
  120.     // 创建一个TCP套接字  
  121.     sock_fd = socket(AF_INET, SOCK_STREAM,0);  
  122.     if (sock_fd < 0) {  
  123.         my_err("socket", __LINE__);  
  124.     }  
  125.   
  126.     // 设置该套接字使之可以重新绑定端口  
  127.     optval = 1;  
  128.     if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,  
  129.                    (void *)&optval, sizeof(int)) < 0) {  
  130.         my_err("setsockopt", __LINE__);  
  131.     }  
  132.   
  133.     // 初始化服务器端地址结构  
  134.     memset(&serv_addr, 0, sizeof (struct sockaddr_in));  
  135.     serv_addr.sin_family = AF_INET;  
  136.     serv_addr.sin_port = htons(SERV_PORT);  
  137.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  
  138.   
  139.     // 将套接字绑定到本地端口  
  140.     if (bind(sock_fd, (struct sockaddr *)&serv_addr,  
  141.              sizeof (struct sockaddr_in)) < 0) {  
  142.         my_err("bind", __LINE__);  
  143.     }  
  144.   
  145.     // 将套接字转化为监听套接字  
  146.     if (listen(sock_fd, LISTENQ) < 0) {  
  147.         my_err("listen", __LINE__);  
  148.     }  
  149.   
  150.     cli_len = sizeof (struct sockaddr_in);  
  151.     while (1) {  
  152.         // 通过accept接受客户端的连接请求,并返回连接套接字用于收发数据  
  153.         conn_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &cli_len);  
  154.         if (conn_fd < 0) {  
  155.             my_err("accept", __LINE__);  
  156.         }  
  157.   
  158.         printf("accept a new client, ip:%s\n", inet_ntoa(cli_addr.sin_addr));  
  159.         // 创建一个子进程处理刚刚接受的连接请求  
  160.         if ( (pid = fork()) == 0 ) {    // 子进程  
  161.             while(1) {  
  162.                 memset(recv_buf, 0, sizeof(recv_buf));  
  163.                 if ((ret = recv(conn_fd, recv_buf, sizeof (recv_buf), 0)) < 0) {  
  164.                     perror("recv");  
  165.                     exit(1);  
  166.                 }  
  167.                 recv_buf[ret-1] = '\0'; // 将数据结束标志'\n'替换成字符串结束标志  
  168.                 if (flag_recv == USERNAME) {    // 接收到的是用户名  
  169.                     name_num = find_name(recv_buf);  
  170.                     switch (name_num) {  
  171.                     case -1:  
  172.                         send_data(conn_fd, "n\n");  
  173.                         break;  
  174.                     case -2:  
  175.                         exit(1);  
  176.                         break;  
  177.                     default:  
  178.                         send_data(conn_fd, "y\n");  
  179.                         flag_recv = PASSWORD;  
  180.                         break;  
  181.                     }  
  182.                 } else if (flag_recv == PASSWORD) {  // 接收到的是密码  
  183.                     if (strncmp(users[name_num].password, recv_buf, strlen(users[name_num].password)) == 0) {  
  184.                         send_data(conn_fd, "y\n");  
  185.                         send_data(conn_fd, "Welcome login my tcp server\n");  
  186.                         printf("%s login\n", users[name_num].username);  
  187.                         break; // 跳出while循环  
  188.                     } else  
  189.                         send_data(conn_fd, "n\n");  
  190.                 }  
  191.             }  
  192.             close(sock_fd);  
  193.             close(conn_fd);  
  194.             exit(0);  // 结束子进程  
  195.         } else {   // 父进程关闭刚刚接受的连接请求,执行accept等待其他连接请求  
  196.             close(conn_fd);  
  197.         }  
  198.     }  
  199.   
  200.     return 0;  
  201. }  
(2)客户端client.c:
[html] view plaincopy
  1. #include <sys/types.h>  
  2. #include <sys/socket.h>  
  3. #include <unistd.h>  
  4. #include <stdio.h>  
  5. #include <string.h>  
  6. #include <errno.h>  
  7. #include <stdlib.h>  
  8. #include <netinet/in.h>  
  9. #include <arpa/inet.h>  
  10. #define BUFSIZE 1024  
  11.   
  12. #define INVALID_USERINFO    'n' // 用户信息无效  
  13. #define VALID_USERINFO      'y' // 用户信息有效  
  14. /*自定义的错误处理函数*/  
  15. void my_err(const char * err_string, int line)  
  16. {  
  17.     fprintf(stderr, "line:%d  ", line);  
  18.     perror(err_string);  
  19.     exit(1);  
  20. }  
  21.   
  22. /*  
  23. * 函数名: my_recv  
  24. * 描 述 : 从套接字上读取一次数据(以'\n'为结束标志)  
  25. * 参 数 : conn_fd     -- 从该连接套接字上接收数据  
  26. *     data_buf  -- 读取到的数据保存在此缓冲中  
  27. *     len       -- data_buf所指向的空间长度  
  28. * 返回值: 出错返回-1, 服务器端已关闭连接则返回0, 成功返回读取的字节数  
  29. */  
  30. int my_recv(int conn_fd, char *data_buf, int len)  
  31. {  
  32.     static  char    recv_buf[BUFSIZE];  // 自定义缓冲区,BUFSIZE定义在my_recv.h中  
  33.     static  char    *pread;         // 指向下一次读取数据的位置  
  34.     static  int len_remain = 0;     // 自定义缓冲区中剩余字节数  
  35.     int         i;  
  36.   
  37.     // 如果自定义缓冲区中没有数据,则从套接字读取数据  
  38.     if (len_remain <= 0) {  
  39.         if ((len_remain =recv(conn_fd, recv_buf, sizeof (recv_buf), 0)) < 0) {  
  40.             my_err("recv", __LINE__);  
  41.         } else if (len_remain == 0) {   // 目的计算机端的socket连接关闭  
  42.             return 0;  
  43.         }  
  44.         pread = recv_buf;   // 重新初始化pread指针  
  45.     }  
  46.   
  47.     // 从自定义缓冲区中读取一次数据  
  48.     for (i=0; *pread != '\n'; i++) {  
  49.         if (i > len) {   // 防止指针越界  
  50.             return -1;  
  51.         }  
  52.         data_buf[i] = *pread++;  
  53.         len_remain--;  
  54.     }  
  55.   
  56.     // 去除结束标志  
  57.     len_remain--;  
  58.     pread++;  
  59.   
  60.     return i;   // 读取成功  
  61. }  
  62. /*获取用户输入存入到buf,buf的长度为len,用户输入数据以'\n'为结束标志*/  
  63. int get_userinfo(char *buf, int len)  
  64. {  
  65.     int i;  
  66.     int c;  
  67.   
  68.     if (buf == NULL) {  
  69.         return -1;  
  70.     }  
  71.   
  72.     i = 0;  
  73.     while ( ((c = getchar()) != '\n') && (c != EOF) && (i < len-2) ) {  
  74.         buf[i++] = c;  
  75.     }  
  76.     buf[i++] = '\n';  
  77.     buf[i++] = '\0';  
  78.   
  79.     return 0;  
  80. }  
  81.   
  82. // 输入用户名,然后通过fd发送出去  
  83. void input_userinfo(int conn_fd, const char *string)  
  84. {  
  85.     char    input_buf[32];  
  86.     char    recv_buf[BUFSIZE];  
  87.     int flag_userinfo;  
  88.     int count = 0;  
  89.     // 输入用户信息直到正确为止  
  90.     do {  
  91.         printf("%s:", string);  
  92.         if (get_userinfo(input_buf, 32) < 0) {  
  93.             printf("error return from get_userinfo\n");  
  94.             exit(1);  
  95.         }  
  96.   
  97.         if (send(conn_fd, input_buf, strlen(input_buf), 0) < 0) {  
  98.             my_err("send", __LINE__);  
  99.         }  
  100.   
  101.         // 从连接套接字上读取一次数据  
  102.         if (my_recv(conn_fd, recv_buf, sizeof (recv_buf)) < 0) {  
  103.             printf("data is too long\n");  
  104.             exit(1);  
  105.         }  
  106.   
  107.         if (recv_buf[0] == VALID_USERINFO) {  
  108.             flag_userinfo = VALID_USERINFO;  
  109.         } else {  
  110.             count++;  
  111.             if (count >= 3) {  
  112.                 printf("input %s error for three times,exit!\n", string);  
  113.                 exit(-1);  
  114.             }  
  115.             printf("%s error,input again!\n", string);  
  116.             flag_userinfoINVALID_USERINFO;  
  117.         }  
  118.     } while(flag_userinfo == INVALID_USERINFO);  
  119. }  
  120.   
  121. int main(int argc, char **argv)  
  122. {  
  123.     int         i;  
  124.     int         ret;  
  125.     int         conn_fd;  
  126.     int         serv_port;  
  127.     struct sockaddr_in  serv_addr;  
  128.     char            recv_buf[BUFSIZE];  
  129.   
  130.     // 检查参数个数  
  131.     if (argc != 5) {  
  132.         printf("Usage: [-p] [serv_port] [-a] [serv_address]\n");  
  133.         exit(1);  
  134.     }  
  135.   
  136.     // 初始化服务器端地址结构  
  137.     memset(&serv_addr, 0, sizeof (struct sockaddr_in));  
  138.     serv_addr.sin_family = AF_INET;  
  139.     // 从命令行获取服务器端的端口与地址  
  140.     for (i=1; i<argc; i++) {  
  141.         if (strcmp("-p", argv[i]) == 0) {  
  142.             serv_port = atoi(argv[i+1]);  
  143.             if (serv_port < 0 || serv_port > 65535) {  
  144.                 printf("invalid serv_addr.sin_port\n");  
  145.                 exit(1);  
  146.             } else {  
  147.                 serv_addr.sin_port = htons(serv_port);  
  148.             }  
  149.             continue;  
  150.         }  
  151.   
  152.         if (strcmp("-a", argv[i]) == 0) {  
  153.             if (inet_aton(argv[i+1], &serv_addr.sin_addr) == 0) {  
  154.                 printf("invalid server ip address\n");  
  155.                 exit(1);  
  156.             }  
  157.             continue;  
  158.         }  
  159.     }  
  160.     // 检测是否少输入了某项参数  
  161.     if (serv_addr.sin_port == 0 || serv_addr.sin_addr.s_addr == 0) {  
  162.         printf("Usage: [-p] [serv_addr.sin_port] [-a][serv_address]\n");  
  163.         exit(1);  
  164.     }  
  165.   
  166.     // 创建一个TCP套接字  
  167.     conn_fd = socket(AF_INET, SOCK_STREAM,0);  
  168.     if (conn_fd < 0) {  
  169.         my_err("socket", __LINE__);  
  170.     }  
  171.   
  172.     // 向服务器端发送连接请求  
  173.     if (connect(conn_fd, (struct sockaddr *)&serv_addr, sizeof (struct sockaddr)) < 0) {  
  174.         my_err("connect", __LINE__);  
  175.     }  
  176.   
  177.     // 输入用户名和密码  
  178.     input_userinfo(conn_fd, "username");  
  179.     input_userinfo(conn_fd, "password");  
  180.   
  181.     // 读取欢迎信息并打印出来  
  182.     if ((ret = my_recv(conn_fd, recv_buf, sizeof (recv_buf))) < 0) {  
  183.         printf("data is too long\n");  
  184.         exit(1);  
  185.     }  
  186.     for (i=0; i<ret; i++) {  
  187.         printf("%c", recv_buf[i]);  
  188.     }  
  189.     printf("\n");  
  190.   
  191.     close(conn_fd);  
  192.     return 0;  
  193. }  
(3)编译运行:
[html] view plaincopy
  1. gcc -o server server.c  
  2. ./server  
  3. gcc -o client client.c  
  4. ./client -p 4507 -a 127.0.0.1  

3、socket文件传输(从server端下载文件)

(1)file_server.c:
[html] view plaincopy
  1. #include <netinet/in.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <sys/socket.h>  
  7. #include <strings.h>  
  8.   
  9. #define HELLO_WORLD_SERVER_PORT 6666  
  10. #define LENGTH_OF_LISTENQ_QUEUE 20  
  11. #define BUFFER_SIZE 1024  
  12. #define FILE_NAME_MAX_SIZE 512  
  13. int main(int argc, char *argv[])  
  14. {  
  15.     struct sockaddr_in server_addr;  
  16.     bzero(&server_addr, sizeof(server_addr));  
  17.     server_addr.sin_family = AF_INET;  
  18.     server_addr.sin_addr.s_addr = htons(INADDR_ANY);  
  19.     server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);  
  20.   
  21.     int server_socket = socket(AF_INET, SOCK_STREAM, 0);  
  22.     if (server_socket < 0) {  
  23.         printf("create socket failed!\n");  
  24.         exit(1);  
  25.     }  
  26.     if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))) {  
  27.         printf("bind socket failed!\n");  
  28.         exit(1);  
  29.     }  
  30.     if (listen(server_socket, LENGTH_OF_LISTENQ_QUEUE)) {  
  31.         printf("listen socket failed!\n");  
  32.         exit(1);  
  33.     }  
  34.     while (1) {  
  35.         struct sockaddr_in client_addr;  
  36.         socklen_t length = sizeof(client_addr);  
  37.         int new_server_scoket = accept(server_socket, (struct sockaddr*)&client_addr, &length);  
  38.         if (new_server_scoket < 0) {  
  39.             printf("accept socket failed!\n");  
  40.             break;  
  41.         }  
  42.         char buffer[BUFFER_SIZE];  
  43.         bzero(buffer, BUFFER_SIZE);  
  44.         length = recv(new_server_scoket, buffer, BUFFER_SIZE, 0);  
  45.         if (length < 0) {  
  46.             printf("recv data failed!\n");  
  47.             break;  
  48.         }  
  49.         char file_name[FILE_NAME_MAX_SIZE + 1];  
  50.         bzero(file_name, FILE_NAME_MAX_SIZE + 1);  
  51.         strncpy(file_name, buffer, strlen(file_name) > FILE_NAME_MAX_SIZE ? FILE_NAME_MAX_SIZE : strlen(buffer));  
  52.         FILE *fp = fopen(file_name, "r");  
  53.         if (fp == NULL) {  
  54.             printf("File: %s not found\n", file_name);  
  55.         }  
  56.         else {  
  57.             bzero(buffer, BUFFER_SIZE);  
  58.             int file_length = 0;  
  59.             while((file_length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) {  
  60.                 printf("file_length = %d\n", file_length);  
  61.                 if (send(new_server_scoket, buffer, file_length, 0) < 0) {  
  62.                     printf("send file: %s failed\n", file_name);  
  63.                     break;  
  64.                 }  
  65.                 bzero(buffer, BUFFER_SIZE);  
  66.             }  
  67.             fclose(fp);  
  68.             printf("file: %s trandfer finished\n", file_name);  
  69.         }  
  70.         close(new_server_scoket);  
  71.     }  
  72.     close(server_socket);  
  73.     return 0;  
  74. }  
(2)file_client.c:
[html] view plaincopy
  1. #include <netinet/in.h>  
  2. #include <stdio.h>  
  3. #include <stdlib.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <sys/socket.h>  
  7. #include <strings.h>  
  8.   
  9. #define HELLO_WORLD_SERVER_PORT 6666  
  10. #define BUFFER_SIZE 1024  
  11. #define FILE_NAME_MAX_SIZE 512  
  12.   
  13. int main(int argc, char *argv[])   
  14. {  
  15.     if (argc != 2) {  
  16.         printf("use:[./run][server_ipaddress]\n");  
  17.         exit(1);  
  18.     }  
  19.     struct sockaddr_in client_addr;  
  20.     bzero(&client_addr,sizeof(client_addr));  
  21.     client_addr.sin_family = AF_INET;  
  22.     if (inet_aton(argv[1], &client_addr.sin_addr) == 0) {  
  23.         printf("server ip address error!\n");  
  24.         exit(1);  
  25.     }  
  26.     client_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);  
  27.     socklen_t client_addr_length = sizeof(client_addr);  
  28.     int client_socket = socket(AF_INET, SOCK_STREAM, 0);  
  29.     if (client_socket < 0) {  
  30.         printf("create socket failed\n");  
  31.         exit(1);  
  32.     }  
  33.     if (connect(client_socket, (struct sockaddr*)&client_addr, client_addr_length) < 0) {  
  34.         printf("can not connect to address\n");  
  35.         exit(1);  
  36.     }  
  37.     char file_name[FILE_NAME_MAX_SIZE + 1];  
  38.     bzero(file_name, FILE_NAME_MAX_SIZE + 1);  
  39.     printf("please input file name:");  
  40.     scanf("%s", file_name);  
  41.   
  42.     char buffer[BUFFER_SIZE];  
  43.     bzero(buffer, BUFFER_SIZE);  
  44.     strncpy(buffer, file_name, strlen(file_name) > BUFFER_SIZE ? BUFFER_SIZE : strlen(file_name));  
  45.     send(client_socket, buffer, BUFFER_SIZE, 0);  
  46.     FILE *fp = fopen(file_name, "w");  
  47.     if (fp == NULL) {  
  48.         printf("file can not open\n");  
  49.         exit(1);  
  50.     }  
  51.     bzero(buffer, BUFFER_SIZE);  
  52.     int length = 0;  
  53.     while (length = recv(client_socket, buffer, BUFFER_SIZE, 0)) {  
  54.         if (length < 0) {  
  55.             printf("recv failed\n");  
  56.             break;  
  57.         }  
  58.         int write_length = fwrite(buffer, sizeof(char), length, fp);  
  59.         if (write_length < length) {  
  60.             printf("file write failed\n");  
  61.             break;  
  62.         }  
  63.         bzero(buffer, BUFFER_SIZE);  
  64.     }  
  65.     printf("recieve file: %s from server %s finished!\n", file_name, argv[1]);  
  66.     close(fp);  
  67.     close(client_socket);  
  68.     return 0;  
  69. }  
(3)编译运行
[html] view plaincopy
  1. gcc -o server file_server.c  
  2. ./server  
  3. gcc -o client file_client.c  
  4. ./client 127.0.0.1  
server显示:

client显示:

      注:server和client放在不同的目录下,需要传输的文件yang.txt与server在同一目录下。

4、模拟http服务器

(1)http服务器server.c:

[html] view plaincopy
  1. #include <stdarg.h>  
  2. #include <errno.h>  
  3. #include <stdio.h>  
  4. #include <fcntl.h>  
  5. #include <unistd.h>  
  6. #include <string.h>  
  7. #include <time.h>  
  8. #include <sys/types.h>  
  9. #include <sys/stat.h>  
  10. #include <dirent.h>  
  11. #include <errno.h>  
  12. #include <netinet/in.h>  
  13. #include <sys/socket.h>  
  14. #include <resolv.h>  
  15. #include <arpa/inet.h>  
  16. #include <stdlib.h>  
  17. #include <signal.h>  
  18. #include <strings.h>  
  19. #define DEFAULTIP "127.0.0.1"  
  20. #define DEFAULTPORT "4040"  
  21. #define DEFAULTBACK "10"  
  22. #define DEFAULTDIR "/tmp/http/dir"  
  23. #define DEFAULTLOG "/tmp/http/log"  
  24.   
  25. void prterrmsg(char *msg);  
  26. #define prterrmsg(msg)        { perror(msg); abort(); }  
  27. void wrterrmsg(char *msg);  
  28. #define wrterrmsg(msg)        { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }  
  29.   
  30. void prtinfomsg(char *msg);  
  31. #define prtinfomsg(msg)        { fputs(msg, stdout);  }  
  32. void wrtinfomsg(char *msg);  
  33. #define wrtinfomsg(msg)        {  fputs(msg, logfp); fflush(logfp);}  
  34.   
  35. #define MAXBUF        1024  
  36.   
  37. char buffer[MAXBUF + 1];  
  38. char *host = 0;  
  39. char *port = 0;  
  40. char *back = 0;  
  41. char *dirroot = 0;  
  42. char *logdir = 0;  
  43. unsigned char daemon_y_n = 0;  
  44. FILE *logfp;  
  45.   
  46. #define MAXPATH        150  
  47.   
  48. /*----------------------------------------  
  49.  *--- dir_up - 查找dirpath所指目录的上一级目录  
  50.  *----------------------------------------  
  51.  */  
  52. char *dir_up(char *dirpath)  
  53. {  
  54.     static char Path[MAXPATH];  
  55.     int len;  
  56.   
  57.     strcpy(Path, dirpath);  
  58.     len = strlen(Path);  
  59.     if (len > 1 && Path[len - 1] == '/')  
  60.         len--;  
  61.     while (Path[len - 1] != '/' && len > 1)  
  62.         len--;  
  63.     Path[len] = 0;  
  64.     return Path;  
  65. }  
  66.   
  67. /*------------------------------------------------------  
  68.  *--- AllocateMemory - 分配空间并把d所指的内容复制  
  69.  *------------------------------------------------------  
  70.  */  
  71. void AllocateMemory(char **s, int l, char *d)  
  72. {  
  73.     *s = (char *)malloc(l + 1);  
  74.     bzero(*s, l + 1);  
  75.     memcpy(*s, d, l);  
  76. }  
  77. /*------------------------------------------------------  
  78.  *--- GiveResponse - 把Path所指的内容发送到client_sock去  
  79.  *-------------------如果Path是一个目录,则列出目录内容  
  80.  *-------------------如果Path是一个文件,则下载文件  
  81.  *------------------------------------------------------  
  82.  */  
  83. void GiveResponse(FILE * client_sock, char *Path)  
  84. {  
  85.     struct dirent *dirent;  
  86.     struct stat info;  
  87.     char Filename[MAXPATH];  
  88.     DIR *dir;  
  89.     int fd, len, ret;  
  90.     char *p, *realPath, *realFilename, *nport;  
  91.   
  92.     /* 获得实际工作目录或文件 */  
  93.     len = strlen(dirroot) + strlen(Path) + 1;  
  94.     realPath = (char *)malloc(len + 1);  
  95.     bzero(realPath, len + 1);  
  96.     sprintf(realPath, "%s/%s", dirroot, Path);  
  97.   
  98.     /* 获得实际工作端口 */  
  99.     len = strlen(port) + 1;  
  100.     nport = (char *)malloc(len + 1);  
  101.     bzero(nport, len + 1);  
  102.     sprintf(nport, ":%s", port);  
  103.   
  104.     /* 获得实际工作目录或文件的信息以判断是文件还是目录 */  
  105.     if (stat(realPath, &info)) {  
  106.         fprintf(client_sock,  
  107.                 "HTTP/1.1 200 OK\r\nServer: DAS by Centos\r\nConnection: close\r\n\r\n"  
  108.                 "<html>"  
  109.                 "<meta charset=\"UTF-8\"/>"  
  110.                 "<head><title>%d - %s</title></head>"  
  111.                 "<body><font size=+4>Linux下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  112.                 "<table border cols=3 width=\"100%%\">"  
  113.                 , errno, strerror(errno));  
  114.         fprintf(client_sock,  
  115.                 "</table><font color=\"CC0000\" size=+2>请向管理员咨询为何出现如下错误提示:\n%s %s</font></body></html>",  
  116.                 Path, strerror(errno));  
  117.         goto out;  
  118.     }  
  119.     /* 处理浏览文件请求,即下载文件 */  
  120.     if (S_ISREG(info.st_mode)) {  
  121.         fd = open(realPath, O_RDONLY);  
  122.         len = lseek(fd, 0, SEEK_END);  
  123.         p = (char *) malloc(len + 1);  
  124.         bzero(p, len + 1);  
  125.         lseek(fd, 0, SEEK_SET);  
  126.         ret = read(fd, p, len);  
  127.         close(fd);  
  128.         fprintf(client_sock,  
  129.                 "HTTP/1.1 200 OK\r\nServer: DAS by Centos\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n",  
  130.                 len);  
  131.         fwrite(p, len, 1, client_sock);  
  132.         free(p);  
  133.     } else if (S_ISDIR(info.st_mode)) {  
  134.         /* 处理浏览目录请求 */  
  135.         dir = opendir(realPath);  
  136.         fprintf(client_sock,  
  137.                 "HTTP/1.1 200 OK\r\nServer: DAS by Centos\r\nConnection: close\r\n\r\n"  
  138.                 "<html>"  
  139.                 "<meta charset=\"UTF-8\"/>"  
  140.                 "<head><title>%s</title></head>"  
  141.                 "<body><font size=+4>Linux下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  142.                 "<table border cols=3 width=\"100%%\">", Path);  
  143.         fprintf(client_sock,  
  144.                 "<caption><font size=+3>目录 %s</font></caption>\n",  
  145.                 Path);  
  146.         fprintf(client_sock,  
  147.                 "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n");  
  148.         if (dir == 0) {  
  149.             fprintf(client_sock,  
  150.                     "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",  
  151.                     strerror(errno));  
  152.             return;  
  153.         }  
  154.         /* 读取目录里的所有内容 */  
  155.         while ((dirent = readdir(dir)) != 0) {  
  156.             if (strcmp(Path, "/") == 0)  
  157.                 sprintf(Filename, "/%s", dirent->d_name);  
  158.             else  
  159.                 sprintf(Filename, "%s/%s", Path, dirent->d_name);  
  160.             fprintf(client_sock, "<tr>");  
  161.             len = strlen(dirroot) + strlen(Filename) + 1;  
  162.             realFilename = (char *)malloc(len + 1);  
  163.             bzero(realFilename, len + 1);  
  164.             sprintf(realFilename, "%s/%s", dirroot, Filename);  
  165.             if (stat(realFilename, &info) == 0) {  
  166.                 if (strcmp(dirent->d_name, "..") == 0)  
  167.                     fprintf(client_sock,  
  168.                             "<td><a href=\"http://%s%s%s\">(parent)</a></td>",  
  169.                             host, atoi(port) == 80 ? "" : nport,  
  170.                             dir_up(Path));  
  171.                 else  
  172.                     fprintf(client_sock,  
  173.                             "<td><a href=\"http://%s%s%s\">%s</a></td>",  
  174.                             host, atoi(port) == 80 ? "" : nport, Filename,  
  175.                             dirent->d_name);  
  176.                 if (S_ISDIR(info.st_mode))  
  177.                     fprintf(client_sock, "<td>目录</td>");  
  178.                 else if (S_ISREG(info.st_mode))  
  179.                     fprintf(client_sock, "<td>%d</td>", info.st_size);  
  180.                 else if (S_ISLNK(info.st_mode))  
  181.                     fprintf(client_sock, "<td>链接</td>");  
  182.                 else if (S_ISCHR(info.st_mode))  
  183.                     fprintf(client_sock, "<td>字符设备</td>");  
  184.                 else if (S_ISBLK(info.st_mode))  
  185.                     fprintf(client_sock, "<td>块设备</td>");  
  186.                 else if (S_ISFIFO(info.st_mode))  
  187.                     fprintf(client_sock, "<td>FIFO</td>");  
  188.                 else if (S_ISSOCK(info.st_mode))  
  189.                     fprintf(client_sock, "<td>Socket</td>");  
  190.                 else  
  191.                     fprintf(client_sock, "<td>(未知)</td>");  
  192.                 fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));  
  193.             }  
  194.             fprintf(client_sock, "</tr>\n");  
  195.             free(realFilename);  
  196.         }  
  197.         fprintf(client_sock, "</table></center></body></html>");  
  198.     } else {  
  199.         /* 既非常规文件又非目录,禁止访问 */  
  200.         fprintf(client_sock,  
  201.                 "HTTP/1.1 200 OK\r\nServer: DAS by Centos\r\nConnection: close\r\n\r\n"  
  202.                 "<html>"  
  203.                 "<meta charset=\"UTF-8\"/>"  
  204.                 "<head><title>permission denied</title></head>"  
  205.                 "<body><font size=+4>Linux下目录访问服务器</font><br><hr width=\"100%%\"><br><center>"  
  206.                 "<table border cols=3 width=\"100%%\">");  
  207.         fprintf(client_sock,  
  208.                 "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html>",  
  209.                 Path);  
  210.     }  
  211. out:  
  212.     free(realPath);  
  213.     free(nport);  
  214. }  
  215.   
  216. /*------------------------------------------------------  
  217.  *--- getoption - 分析取出程序的参数  
  218.  *------------------------------------------------------  
  219.  */  
  220. void getoption(int argc, char **argv)  
  221. {  
  222.     //    int c, len;  
  223.     //    char *p = 0;  
  224.     //  
  225.     //    opterr = 0;  
  226.     //    while (1) {  
  227.     //        int option_index = 0;  
  228.     //        static struct option long_options[] = {  
  229.     //            {"host", 1, 0, 0},  
  230.     //            {"port", 1, 0, 0},  
  231.     //            {"back", 1, 0, 0},  
  232.     //            {"dir", 1, 0, 0},  
  233.     //            {"log", 1, 0, 0},  
  234.     //            {"daemon", 0, 0, 0},  
  235.     //            {0, 0, 0, 0}  
  236.     //        };  
  237.     //        /* 本程序支持如一些参数:  
  238.     //         * --host IP地址 或者 -H IP地址  
  239.     //         * --port 端口 或者 -P 端口  
  240.     //         * --back 监听数量 或者 -B 监听数量  
  241.     //         * --dir 网站根目录 或者 -D 网站根目录  
  242.     //         * --log 日志存放路径 或者 -L 日志存放路径  
  243.     //         * --daemon 使程序进入后台运行模式  
  244.     //         */  
  245.     //        c = getopt_long(argc, argv, "H:P:B:D:L",  
  246.     //                        long_options, &option_index);  
  247.     //        if (c == -1 || c == '?')  
  248.     //            break;  
  249.     //  
  250.     //        if(optarg)        len = strlen(optarg);  
  251.     //        else        len = 0;  
  252.     //  
  253.     //        if ((!c && !(strcasecmp(long_options[option_index].name, "host")))  
  254.     //            || c == 'H')  
  255.     //            p = host = malloc(len + 1);  
  256.     //        else if ((!c  
  257.     //                  &&  
  258.     //                  !(strcasecmp(long_options[option_index].name, "port")))  
  259.     //                 || c == 'P')  
  260.     //            p = port = malloc(len + 1);  
  261.     //        else if ((!c  
  262.     //                  &&  
  263.     //                  !(strcasecmp(long_options[option_index].name, "back")))  
  264.     //                 || c == 'B')  
  265.     //            p = back = malloc(len + 1);  
  266.     //        else if ((!c  
  267.     //                  && !(strcasecmp(long_options[option_index].name, "dir")))  
  268.     //                 || c == 'D')  
  269.     //            p = dirroot = malloc(len + 1);  
  270.     //        else if ((!c  
  271.     //                  && !(strcasecmp(long_options[option_index].name, "log")))  
  272.     //                 || c == 'L')  
  273.     //            p = logdir = malloc(len + 1);  
  274.     //        else if ((!c  
  275.     //                  &&  
  276.     //                  !(strcasecmp  
  277.     //                    (long_options[option_index].name, "daemon")))) {  
  278.     //            daemon_y_n = 1;  
  279.     //            continue;  
  280.     //        }  
  281.     //        else  
  282.     //            break;  
  283.     //        bzero(p, len + 1);  
  284.     //        memcpy(p, optarg, len);  
  285.     //    }  
  286. }  
  287.   
  288. int main(int argc, char **argv)  
  289. {  
  290.     struct sockaddr_in addr;  
  291.     int sock_fd, addrlen;  
  292.   
  293.     /* 获得程序工作的参数,如 IP 、端口、监听数、网页根目录、目录存放位置等 */  
  294.     //getoption(argc, argv);  
  295.   
  296.     if (!host) {  
  297.         addrlen = strlen(DEFAULTIP);  
  298.         AllocateMemory(&host, addrlen, DEFAULTIP);  
  299.     }  
  300.     if (!port) {  
  301.         addrlen = strlen(DEFAULTPORT);  
  302.         AllocateMemory(&port, addrlen, DEFAULTPORT);  
  303.     }  
  304.     if (!back) {  
  305.         addrlen = strlen(DEFAULTBACK);  
  306.         AllocateMemory(&back, addrlen, DEFAULTBACK);  
  307.     }  
  308.     if (!dirroot) {  
  309.         addrlen = strlen(DEFAULTDIR);  
  310.         AllocateMemory(&dirroot, addrlen, DEFAULTDIR);  
  311.     }  
  312.     if (!logdir) {  
  313.         addrlen = strlen(DEFAULTLOG);  
  314.         AllocateMemory(&logdir, addrlen, DEFAULTLOG);  
  315.     }  
  316.   
  317.     printf  
  318.             ("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n",  
  319.              host, port, back, dirroot, logdir, daemon_y_n?"":"不", getpid());  
  320.   
  321.     /* fork() 两次处于后台工作模式下 */  
  322.     if (daemon_y_n) {  
  323.         if (fork())  
  324.             exit(0);  
  325.         if (fork())  
  326.             exit(0);  
  327.         close(0), close(1), close(2);  
  328.         logfp = fopen(logdir, "a+");  
  329.         if (!logfp)  
  330.             exit(0);  
  331.     }  
  332.   
  333.     /* 处理子进程退出以免产生僵尸进程 */  
  334.     signal(SIGCHLD, SIG_IGN);  
  335.   
  336.     /* 创建 socket */  
  337.     if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {  
  338.         if (!daemon_y_n) {  
  339.             prterrmsg("socket()");  
  340.         } else {  
  341.             wrterrmsg("socket()");  
  342.         }  
  343.     }  
  344.   
  345.     /* 设置端口快速重用 */  
  346.     addrlen = 1;  
  347.     setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen,  
  348.                sizeof(addrlen));  
  349.   
  350.     addr.sin_family = AF_INET;  
  351.     addr.sin_port = htons(atoi(port));  
  352.     addr.sin_addr.s_addr = htonl(INADDR_ANY);//htonl(INADDR_ANY);  
  353.     addrlen = sizeof(struct sockaddr_in);  
  354.     /* 绑定地址、端口等信息 */  
  355.     if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) {  
  356.         if (!daemon_y_n) {  
  357.             prterrmsg("bind()");  
  358.         } else {  
  359.             wrterrmsg("bind()");  
  360.         }  
  361.     }  
  362.     /* 开启临听 */  
  363.     if (listen(sock_fd, atoi(back)) < 0) {  
  364.         if (!daemon_y_n) {  
  365.             prterrmsg("listen()");  
  366.         } else {  
  367.             wrterrmsg("listen()");  
  368.         }  
  369.     }  
  370.     while (1) {  
  371.         int len;  
  372.         int new_fd;  
  373.         addrlen = sizeof(struct sockaddr_in);  
  374.         /* 接受新连接请求 */  
  375.         new_fd = accept(sock_fd, (struct sockaddr *) &addr, (socklen_t *)&addrlen);  
  376.         if (new_fd < 0) {  
  377.             if (!daemon_y_n) {  
  378.                 prterrmsg("accept()");  
  379.             } else {  
  380.                 wrterrmsg("accept()");  
  381.             }  
  382.             break;  
  383.         }  
  384.         bzero(buffer, MAXBUF + 1);  
  385.         sprintf(buffer, "连接来自于: %s:%d\n",  
  386.                 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));  
  387.         if (!daemon_y_n) {  
  388.             prtinfomsg(buffer);  
  389.         } else {  
  390.             wrtinfomsg(buffer);  
  391.         }  
  392.         /* 产生一个子进程去处理请求,当前进程继续等待新的连接到来 */  
  393.         if (!fork()) {  
  394.             bzero(buffer, MAXBUF + 1);  
  395.             puts("recving...");  
  396.             if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) {  
  397.                 FILE *ClientFP = fdopen(new_fd, "w");  
  398.                 if (ClientFP == NULL) {  
  399.                     if (!daemon_y_n) {  
  400.                         prterrmsg("fdopen()");  
  401.                     } else {  
  402.                         prterrmsg("fdopen()");  
  403.                     }  
  404.                 } else {  
  405.                     char Req[MAXPATH + 1] = "";  
  406.                     sscanf(buffer, "GET %s HTTP", Req);  
  407.                     bzero(buffer, MAXBUF + 1);  
  408.                     sprintf(buffer, "请求取文件: \"%s\"\n", Req);  
  409.                     if (!daemon_y_n) {  
  410.                         prtinfomsg(buffer);  
  411.                     } else {  
  412.                         wrtinfomsg(buffer);  
  413.                     }  
  414.                     /* 处理用户请求 */  
  415.                     GiveResponse(ClientFP, Req);  
  416.                     fclose(ClientFP);  
  417.                 }  
  418.             }  
  419.             puts("go out");  
  420.             exit(0);  
  421.         }  
  422.         close(new_fd);  
  423.     }  
  424.     close(sock_fd);  
  425.     return 0;  
  426. }  
(2)编译运行(浏览器为客户端):
[html] view plaincopy
  1. gcc -o server server.c  
  2. ./server   
服务器运行:
在浏览器中输入:http://127.0.0.1:4040

注:需建立/tmp/http/dir和/tmp/http/log文件夹,并在dir下建立目录树。

然后在浏览器中点击文件即可下载文件,点击目录可进一步进行查看。点击parent可以返回到上一级目录。
(3)http客户端client.c(从服务器上下载文件并重新命名)
[html] view plaincopy
  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include <netdb.h>  
  4. #include <sys/types.h>  
  5. #include <sys/socket.h>  
  6. #include <sys/socketvar.h>  
  7. #include <strings.h>  
  8. #include <arpa/inet.h>  
  9. #include <unistd.h>  
  10. #include <string.h>  
  11. #include<errno.h>  
  12. int main(int argc, char *argv[])  
  13. {  
  14.     char buffer[1024] = {0};  
  15.     char host_addr[256] = {0};  
  16.     char host_file[256] = {0};  
  17.     char local_file[256] = {0};  
  18.     int sockfd;  
  19.     int send, totalsend;  
  20.     int nbytes;  
  21.     char request[1024] = {0};  
  22.     struct sockaddr_in server_addr;  
  23.     struct hostent *host;  
  24.     if (argc != 2) {  
  25.         fprintf(stderr, "Usage:%s web-address!\n", argv[0]);  
  26.         exit(1);  
  27.     }  
  28.     int portnumber = 4040;  
  29.     strcpy(host_addr, argv[1]);  
  30.     strcpy(host_file, "server.c");  
  31.     if ((host = gethostbyname(argv[1])) == NULL) {  
  32.         fprintf(stderr,"Gethostname error\n", strerror(errno));  
  33.         exit(1);  
  34.     }  
  35.     char ip_str[32] = {0};  
  36.     printf("address: %s\n", inet_ntop(host->h_addrtype, host->h_addr, ip_str, sizeof(ip_str)));  
  37.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {  
  38.         fprintf(stderr,"Socket Error:%s!\n",strerror(errno));  
  39.         exit(1);  
  40.     }  
  41.     bzero(&server_addr, sizeof(server_addr));  
  42.     server_addr.sin_family = AF_INET;  
  43.     server_addr.sin_port = htons(portnumber);  
  44.     server_addr.sin_addr = *((struct in_addr *)host->h_addr);  
  45.     if (connect(sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr)) == -1) {  
  46.         fprintf(stderr,"Connect Error:%s!\n",strerror(errno));  
  47.         exit(1);  
  48.     }  
  49.     sprintf(request, "GET /%s HTTP/1.1\r\nAccept: */*\r\nAccept-Language: zh-cn\r\n  \  
  50.             User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)\r\n  \  
  51.             Host: %s:%d\r\nConnection: Close\r\n\r\n", host_file, host_addr, portnumber);  
  52.     strcpy(local_file, "local.txt");  
  53.     send = 0;  
  54.     totalsend = 0;  
  55.     nbytes = strlen(request);  
  56.     while (totalsend < nbytes) {  
  57.         send = write(sockfd, request + totalsend, nbytes - totalsend);  
  58.         if (send == -1) {  
  59.             printf("send error:%s!\n", strerror(errno));  
  60.             exit(0);  
  61.         }  
  62.         totalsend += send;  
  63.         printf("%d bytes send OK!\n", totalsend);  
  64.     }  
  65.     FILE * fp = fopen(local_file, "a");  
  66.     if(!fp) {  
  67.         printf("create file error:%s!\n", strerror(errno));  
  68.         return 0;  
  69.     }  
  70.     //printf("The following is the response header:\n");  
  71.     int i = 0;  
  72.     /* 连接成功了,接收http响应,response */  
  73.     while((nbytes = read(sockfd, buffer, 1)) == 1) {  
  74.         if (i < 4) {  
  75.             if (buffer[0] == '\r' || buffer[0] == '\n')  
  76.                 i++;  
  77.             else  
  78.                 i = 0;  
  79.             //printf("%c", buffer[0]);  
  80.         }  
  81.         else {  
  82.             fwrite(buffer, 1, 1, fp);/*将http主体信息写入文件*/  
  83.             //printf("%c", buffer[0]);  
  84.             i++;  
  85.             if(i % 1024 == 0)  
  86.                 fflush(fp);   /**每1K时存盘一次**/  
  87.         }  
  88.     }  
  89.     printf("\n");  
  90.     fclose(fp);  
  91.     /* 结束通讯 */  
  92.     close(sockfd);  
  93.     return 0;  
  94. }  

在客户端程序的当前的目录下下载了local.txt,其中的内容是服务器上server.c文件的内容。

三、总结

(1)上述代码在centos上测试通过,只是功能实现,代码执行效率暂未考虑。
(2)若有建议,请留言,在此先感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384415.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程(三)进程间的通信

Linux系统编程&#xff08;三&#xff09;进程间的通信一、为什么需要进程之间的通信&#xff08;IPC&#xff09;&#xff1f;二、管道1.概念2.特质3.原理4.局限性5.代码2.读入数据三、共享存储映射注意事项父子进程通信一、为什么需要进程之间的通信&#xff08;IPC&#xff…

exec 函数族

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187409.html linux系统编程之进程&#xff08;五&#xff09;&#xff1a;exec系列函数&#xff08;execl,execlp,execle,execv,execvp)使用 本节目标&#xff1a; exec替换进程映像exec关联函数组&#xff08;execl、execl…

Linux系统编程(四)信号

Linux系统编程&#xff08;四&#xff09;信号一、什么是信号&#xff1f;1、信号的本质2、信号来源硬件来源软件来源二、常见信号1.可靠信号和不可靠信号2、不可靠信号主要有以下问题:3、可靠信号与不可靠信号注册机制三、信号处理方式四、信号处理过程五、未决信号和阻塞信号…

SIGCHLD信号回收子进程

SIGCHLD信号回收子进程代码问题注意点代码 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <signal.h>void handler(int signo) {int status; pid_t pid;while ((pid waitpid(0, &status…

Wait waitpid

转自&#xff1a;http://www.cnblogs.com/mickole/p/3187770.html linux系统编程之进程&#xff08;六&#xff09;&#xff1a;父进程查询子进程的退出,wait,waitpid 本节目标&#xff1a; 僵进程SIGCHLDwaitwaitpid 一&#xff0c;僵尸进程 当一个子进程先于父进程结束运行时…

Linux C++ 简单爬虫

转载&#xff1a;http://blog.csdn.net/orthocenterchocolate/article/details/38665937 方便易用&#xff0c;传入URL&#xff0c;返回对应页面的内容 [cpp] view plaincopy #include <iostream> #include <string> #include <netdb.h> #include <…

Linux系统编程(七)消息队列

Linux系统编程&#xff08;七&#xff09;消息队列一、什么是消息队列二、消息队列内部原理三、实现消息队列的收发1.发送消息队列2.接收消息队列四、消息队列与命名管道的比较一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都…

基于Linux的SOCKET编程之TCP半双工Client-Server聊天程序

转自&#xff1a;http://blog.csdn.net/apollon_krj/article/details/53398448#0-tsina-1-64987-397232819ff9a47a7b7e80a40613cfe1 所谓半双工通信&#xff0c;即通信双方都可以实现接发数据&#xff0c;但是有一个限制&#xff1a;只能一方发一方收&#xff0c;之后交换收发对…

智能算法(GA、DBO等)求解阻塞流水车间调度问题(BFSP)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

Linux socket编程,对套接字进行封装

转自&#xff1a;http://www.cnblogs.com/-Lei/archive/2012/09/04/2670942.html 下面是对socket操作的封装&#xff0c;因为在Linux下写中文到了windows里面会乱码&#xff0c;所以注释用英文来写&#xff0c;有空再查下解决方法吧 socket.h #ifndef SOCKET_H #define SOCKET_…

Linux系统编程(九)线程同步

Linux系统编程&#xff08;九&#xff09;线程同步一、什么是线程同步&#xff1f;二、互斥量三、条件变量pthread_cond_wait函数pthread_cond_signal函数生产者和消费者模型一、什么是线程同步&#xff1f; 线程同步&#xff0c;指一个线程发出某一功能调用时&#xff0c;在没…

linux网络编程(一)网络基础传输知识

linux网络编程&#xff08;一&#xff09;网络传输基础知识一、什么是协议&#xff1f;二、使用步骤典型协议2.网络应用程序设计模式C/S模式B/S模式优缺点3.分层模型4.TCP/IP四层模型通信过程5.协议格式数据包封装以太网帧格式ARP数据报格式IP段格式UDP数据报格式TCP数据报格式…

Linux 进程学习(四)------ sigaction 函数

转自&#xff1a;http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html 使用 sigaction 函数&#xff1a; signal 函数的使用方法简单&#xff0c;但并不属于 POSIX 标准&#xff0c;在各类 UNIX 平台上的实现不尽相同&#xff0c;因此其用途受 到了一定的限制…

linux网络编程(二)高并发服务器

linux网络编程&#xff08;二&#xff09;高并发服务器错误处理高并发服务器多进程并发服务器客户端错误处理 #include "wrap.h"int Bind(int fd, const struct sockaddr* sa, socklen_t salen) {int ret;if ((ret bind(fd, sa, salen)) < 0){perror("bind…

linux知识(一) 程序、进程与线程

linux知识&#xff08;一&#xff09; 程序、进程与线程程序进程程序如何变成进程&#xff1f;线程线程与进程fork和创建新线程的区别优点程序 程序&#xff1a;程序是已编译好的二进制文件&#xff0c;存储在磁盘中&#xff0c;不占用系统资源 程序包括&#xff1a; RO段&am…

linux知识(二)互斥量、信号量和生产者消费者模型

linux知识&#xff08;二&#xff09;互斥量、信号量和生产者消费者模型一、互斥量产生原因二、信号量生产者消费者模型一、互斥量 产生原因 使用多线程常常会碰到数据混乱的问题&#xff0c;那么使用互斥量&#xff0c;相当于“加锁”的操作&#xff0c;将有助于解决数据混乱…

基于Linux的Socket编程之TCP全双工Server-Client聊天程序

转载&#xff1a;http://blog.csdn.net/apollon_krj/article/details/53437764#0-tsina-1-58570-397232819ff9a47a7b7e80a40613cfe1 一、引言&#xff1a; 由于accept函数、read、write、recv、send等函数都是是阻塞式的&#xff0c;在同一个进程之中&#xff0c;只要有任何一个…

数据结构(一)线性表

数据结构&#xff08;一&#xff09;线性表一、线性表定义二、顺序表定义动态数组三、单链表定义不带头结点带头结点头结点与不带头结点的区别头插法与尾插法双链表循环链表循环单链表循环双链表静态链表一、线性表定义 线性表是具有相同数据类型的n个数据元素的有限序列 特点…

linux网络编程(二)TCP通讯状态

linux网络编程&#xff08;二&#xff09;TCP通讯状态TCP状态转换为什么需要等待2MSL&#xff1f;端口复用TCP状态转换 tcp协议连接开始会经过三次握手&#xff0c;客户端和服务器开始都会处于CLOSED状态 第一次握手&#xff1a;客户端会先发送SYN请求给服务器&#xff0c;客户…

gethostbyname() 函数说明

转载&#xff1a;http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函数说明——用域名或主机名获取IP地址 包含头文件 #include <netdb.h> #include <sys/socket.h> 函数原型 struct hostent *gethostbyna…