Linux C++ 回射服务器

http://blog.csdn.net/qq_25425023/article/details/53914820

回射服务器就是服务端将客户端的数据发送回去。

  

  我实现的回射服务器返回增加了时间。


  服务端代码,可以很容易看懂:

 

[cpp] view plain copy
  1. #include <sys/socket.h>  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include <sys/types.h>  
  5. #include <netinet/in.h>  
  6. #include <time.h>  
  7. #include <unistd.h>  
  8. #include <arpa/inet.h>  
  9. #include <stdlib.h>  
  10.   
  11. #include "../thread_pool.h"  //在上一篇博客中  
  12.   
  13. #define MAX_BUFFER 512  
  14.   
  15. typedef struct sockaddr SSA;  
  16.   
  17. char timebuffer[50];  //存储时间  
  18. char readbuffer[MAX_BUFFER];   //存储客户端数据  
  19. time_t tick;  
  20. //任务类  
  21. class task  
  22. {  
  23. private:  
  24.     int connfd;  //与客户端连接的文件描述符  
  25. public:  
  26.     task(int conn) : connfd(conn)  
  27.     {  
  28.     }  
  29.     ~task(){}  
  30.   
  31.     void doit()  //线程池调用函数  
  32.     {  
  33.     size_t readsize;  
  34.     while((readsize = read(connfd, readbuffer, MAX_BUFFER)) > 0)  //读取客户端数据  
  35.     {  
  36.         printf("%ld get %dbyte\n",(unsigned long)pthread_self()  
  37.          , (int)readsize);   //测试用  
  38.         if(readsize == -1)  //read出错  
  39.         {  
  40.         printf("errno is %s\n", strerror(errno)); //这里输出"onnection reset by peer"  
  41.         continue;  
  42.         }  
  43.         readbuffer[readsize] = '\0';   
  44.         tick = time(NULL); //获取时间  
  45.             snprintf(timebuffer, sizeof(timebuffer), "time : %.24s\r\n",   
  46.         ctime(&tick));  
  47.         strcat(readbuffer, timebuffer);  //时间与客户数据连接到一起  
  48.           
  49.         write(connfd, readbuffer, strlen(readbuffer));  //发送给客户端  
  50.     }  
  51. //  printf("close the connfd\n");  
  52. //  fflush(stdout);  
  53.   
  54.     close(connfd);  
  55.     }  
  56. };  
  57.   
  58. int main(int argc, char *argv[])  
  59. {  
  60.     if(argc != 2)  
  61.     {  
  62.     printf("uasge : %s port", argv[0]);  
  63.     exit(-1);  
  64.     }  
  65.     int sockfd, connfd;  
  66.     struct sockaddr_in serv_addr, cli_addr;  
  67.     int port = atoi(argv[1]);  
  68.     //初始化sockaddr_in  
  69.     serv_addr.sin_family = AF_INET;  
  70.     serv_addr.sin_port = htons(port);  
  71.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //允许任何人连接  
  72.     //创建套接字  
  73.     sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  74.     if(sockfd < 0)  
  75.     {  
  76.     printf("socket error' n");  
  77.     exit(-1);  
  78.     }  
  79.     //绑定  
  80.     bind(sockfd, (SSA *)&serv_addr, sizeof(serv_addr));  
  81.     //监听套接字  
  82.     listen(sockfd, 6);  
  83.     //创建线程池  
  84.     threadpool<task> pool(60, 100);  
  85.     pool.start();  //开启线程池  
  86.     while(1)  
  87.     {  
  88.     socklen_t len = sizeof(cli_addr);  
  89.     connfd = accept(sockfd, (SSA *)&cli_addr, &len);  //接受连接  
  90.     task *ta = new task(connfd);   //新建任务  
  91.     char buf[20];  
  92.     printf("IP %s conn\n", inet_ntop(AF_INET, &cli_addr.sin_addr, buf,   
  93.         sizeof(buf)));  
  94.         while(!pool.append_task(ta))  //添加任务到任务队列  
  95.         printf("loop\n"); //测试用  
  96.     }  
  97.     return 0;  
  98. }  

下面的是客户端的代码:

[cpp] view plain copy
  1. #include <stdio.h>  
  2. #include <sys/socket.h>  
  3. #include <arpa/inet.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <unistd.h>  
  7. #include <netinet/in.h>  
  8. #include <stdlib.h>  
  9.   
  10. int main(int argc, char *argv[])  
  11. {  
  12.     if(argc != 3) //参数不对,退出  
  13.     {  
  14.     printf("usage: %s ip port\n", argv[0]);  
  15.     exit(-1);  
  16.     }  
  17.     int sockfd;  
  18.     struct sockaddr_in serv_addr;  
  19.     int port = atoi(argv[2]);  //将字符串的端口转换称int  
  20.     //初始化服务端的端口和IP地址  
  21.     serv_addr.sin_family = AF_INET;  
  22.     serv_addr.sin_port = htons(port);  //将主机字节序转换称网络字节序  
  23.     inet_pton(AF_INET, argv[1], &serv_addr.sin_addr);  
  24.     //创建套接字  
  25.     sockfd = socket(AF_INET, SOCK_STREAM, 0);  
  26.     //连接  
  27.     connect(sockfd, (struct sockaddr *)&serv_addr,   
  28.         sizeof(serv_addr));  
  29.     char buffer[50];  
  30.     write(sockfd, "hello\n", 6);  //写数据  
  31.     shutdown(sockfd, SHUT_WR);  //解释在下面  
  32.     size_t num = read(sockfd, buffer, sizeof(buffer));  //读数据  
  33.     buffer[num] = '\0';  
  34.     printf("read: %s\n", buffer);  
  35.     shutdown(sockfd, SHUT_RD);  
  36. //    close(sockfd);  
  37.     return 0;  
  38. }  

客户端一开始我使用的是最后来个close的,就是注释那部分,但是多个连接同时来的时候,服务端会出错,具体的出错信息是:Connection reset by peer,重新执行read之后,得到Hello的个数没有少,也就是客户端发送的个数。

然而我客户端写完数据,就关闭写端,读取完数据,再关闭读端,就不会出现这样的错误。

具体原因还不是很清楚,网上没有查找到具体的答案。求大神来解答!!~~

==============================================

终于知道原因了,出错的是在服务端的read函数,read返回-1,而在客户端,发送完数据,就shutdown写端,发送完数据,就会发送FIN包,服务端read返回0,因为read不止被调用一次,第一次读取完数据之后,继续读取,可是客户端没有数据可读,就会出错,而提前关闭客户端写端,所以read那里的WHILE退出,就没有了出错的信息。


同时写了两个shell文件来测试:

[html] view plain copy
  1. #!/bin/bash  
  2.   
  3. for i in `seq 2000`   
  4. do  
  5.     ./client.out 127.0.0.1 8989  
  6. done  

循环 执行2000次。

第二个shell文件:

[html] view plain copy
  1. #!/bin/bash  
  2.   
  3. ./loop.sh > file1 &  
  4. ./loop.sh > file2 &  
  5. ./loop.sh > file3 &  
  6. ./loop.sh > file4 &  
  7. ./loop.sh > file5 &  
  8. wait  
开启5个进程来返问。

执行第二个shell文件

最终,耗时为:

[html] view plain copy
  1. real    0m7.589s  
  2. user    0m0.460s  
  3. sys 0m1.944s  

而且五个File文件中,有Hello的行数数都为2000.


下一篇是实现一个简单小型的web服务器。

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

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

相关文章

TCP第四次挥手为什么要等待2MSL

当客户端进入TIME-WAIT状态的时候(也就是第四次挥手的时候)&#xff0c;必须经过时间计数器设置的时间2MSL(最长报文段寿命)后&#xff0c;才能进入关闭状态&#xff0c;这时为什么呢&#xff1f;&#xff1f;&#xff1f; 这最主要是因为两个理由&#xff1a; 1、为了保证客户…

计算机网络【一】概述+OSI参考模型

网络概述 局域网:覆盖范围小(100m以内)&#xff0c;自己花钱买设备&#xff0c;带宽固定(10M,100M,1000M)&#xff0c;自己维护&#xff08;接入层交换机直接连接电脑、汇聚层交换机直接连接接入层交换机&#xff09; 广域网:距离远&#xff0c;花钱买服务&#xff0c;租带宽&…

单链表逆序的多种方式

https://www.cnblogs.com/eniac12/p/4860642.htmltemplate<class T> void List<T>::Inverse() {if(first NULL) return;LinkNode<T> *p, *prev, *latter; p first->link;   // 当前结点prev NULL;   // 前一结点l…

Linux系统【四】进程间通信-管道

进程间通信&#xff08;IPC Interprocess Communication&#xff09; 进程和进程之间的通信只能通过内核&#xff0c;在内核中提供一块缓冲区进行通信。内核提供的这种机制叫做IPC 在进程间完成数据传输需要借助操作系统提供的特殊方法&#xff0c;如&#xff1a;文件&#xf…

单链表各种操作详解

#include "stdio.h" #include "stdlib.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 20 /* 存储空间初始分配量 */typedef int Status;/* Status是函数的类型,其值是函数结果状态代码&#xff0c;如OK等 */ typedef int…

Linux系统【五】进程间通信-共享内存mmap

mmap函数 #include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);参数&#xff1a; void *addr建立映射区的首地址&#xff0c;由Linux内核指定&#xff0c;所以我们直接传递NULL。也就是说虽然这是一个参宿但是并不…

socket编程 -- epoll模型服务端/客户端通信的实现

https://blog.csdn.net/y396397735/article/details/50680359 本例实现如下功能&#xff1a; 支持多客户端与一个服务端进行通信&#xff0c;客户端给服务端发送字符串数据&#xff0c;服务端将字符串中小写转为大写后发送回客户端&#xff0c;客户端打印输出经转换后的字符串。…

Python3 面向对象程序设计

类的定义 Python使用class关键字来定义类 class Car:def infor(self):print("This is a car") car Car() car.infor()内置方法isinstance()来测试一个对象是否为某个类的实例 self参数 类的 所有实例方法都有一个默认的self参数&#xff0c;并且必须是方法的第一…

计算机网络【二】物理层基础知识

计算机网络的性能 速率&#xff1a;连接在计算机网络上的主机在数字信道上传送数据位数的速率&#xff0c;也成为data rate 或bit rate&#xff0c;单位是b/s,kb/s,Mb/s,Gb/s。 我们平时所讲的宽带的速度是以字为单位的&#xff0c;但是实际中应用一般显示的是字节 &#xff0…

Linux网络编程——tcp并发服务器(多进程)

https://blog.csdn.net/lianghe_work/article/details/46503895一、tcp并发服务器概述一个好的服务器,一般都是并发服务器&#xff08;同一时刻可以响应多个客户端的请求&#xff09;。并发服务器设计技术一般有&#xff1a;多进程服务器、多线程服务器、I/O复用服务器等。二、…

求序列第K大算法总结

参考博客&#xff1a;传送门 在上面的博客中介绍了求序列第K大的几种算法&#xff0c;感觉收益良多&#xff0c;其中最精巧的还是利用快速排序的思想O(n)查询的算法。仔细学习以后我将其中的几个实现了一下。 解法 1&#xff1a; 将乱序数组从大到小进行排序然后取出前K大&a…

Linux网络编程——tcp并发服务器(多线程)

https://blog.csdn.net/lianghe_work/article/details/46504243tcp多线程并发服务器多线程服务器是对多进程服务器的改进&#xff0c;由于多进程服务器在创建进程时要消耗较大的系统资源&#xff0c;所以用线程来取代进程&#xff0c;这样服务处理程序可以较快的创建。据统计&a…

计算机网络【三】物理层数据通信

物理层传输媒介 导向传输媒体&#xff0c;比如光纤和铜线 双绞线&#xff08;屏蔽双绞线STP 五屏蔽双绞线UTP&#xff09;电线扭曲在一起可以降低互相之间的电磁干扰 同轴电缆 (50欧姆的基带同轴电缆&#xff0c;75欧姆的宽带同轴电缆) 10M和100M网络只使用了四根线&#xf…

02_算法分析

02_算法分析 0.1 算法的时间复杂度分析0.1.1 函数渐近增长概念&#xff1a;输入规模n>2时&#xff0c;算法A1的渐近增长小于算法B1 的渐近增长随着输入规模的增大&#xff0c;算法的常数操作可以忽略不计测试二&#xff1a;随着输入规模的增大&#xff0c;与最高次项相乘的常…

Linux网络编程——I/O复用之select详解

https://blog.csdn.net/lianghe_work/article/details/46506143一、I/O复用概述I/O复用概念&#xff1a;解决进程或线程阻塞到某个 I/O 系统调用而出现的技术&#xff0c;使进程不阻塞于某个特定的 I/O 系统调I/O复用使用的场合&#xff1a;1.当客户处理多个描述符&#xff08;…

Linux多进程拷贝文件

学习了mmap以后&#xff0c;实现一个简单的小程序&#xff0c;进行多个进程对一个文件进行拷贝。 Linux mmap共享内存学习可以参考我的另一篇博客&#xff1a;传送门 实现思想 我们可以将原来的文件利用mmap分成多个段分别进行传输。 实现代码 #include<stdio.h> #…

斐波那契查找(Fibonacci Search)和折半查找

两个查找算法都是针对有序数组进行查找&#xff0c;不同点在于分界点的取值不同。 算法介绍 折半查找很简单&#xff0c;每次与当前区间的中点进行比较&#xff0c;然后决定查找前一部分还是后一部分。 Fibonacci查找利用了Fibonacci序列每一项等于前两项和的特点进行划分&a…

Linux网络编程——tcp并发服务器(I/O复用之select)

https://blog.csdn.net/lianghe_work/article/details/46519633与多线程、多进程相比&#xff0c;I/O复用最大的优势是系统开销小&#xff0c;系统不需要建立新的进程或者线程&#xff0c;也不必维护这些线程和进程。代码示例&#xff1a;#include <stdio.h> #include &l…

操作系统【二】死锁问题以及处理方法

死锁的概念 死锁&#xff1a;在并发环境下&#xff0c;个进程因为竞争资源而造成的一种互相等待对方手里的资源&#xff0c;导致各进程都阻塞&#xff0c;无法向前推进的现象。 区别&#xff1a; 饥饿&#xff1a;由于长期得不到想要的资源进程无法向前推进的现象。死循环&a…