Linux C++ 回射服务器

来源:互联网 发布:js获取两位小数函数 编辑:程序博客网 时间:2024/05/21 17:04

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

 

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


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

 

#include <sys/socket.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <netinet/in.h>#include <time.h>#include <unistd.h>#include <arpa/inet.h>#include <stdlib.h>#include "../thread_pool.h"  //在上一篇博客中#define MAX_BUFFER 512typedef struct sockaddr SSA;char timebuffer[50];  //存储时间char readbuffer[MAX_BUFFER];   //存储客户端数据time_t tick;//任务类class task{private:    int connfd;  //与客户端连接的文件描述符public:    task(int conn) : connfd(conn)    {    }    ~task(){}    void doit()  //线程池调用函数    {size_t readsize;while((readsize = read(connfd, readbuffer, MAX_BUFFER)) > 0)  //读取客户端数据{    printf("%ld get %dbyte\n",(unsigned long)pthread_self() , (int)readsize);   //测试用    if(readsize == -1)  //read出错    {printf("errno is %s\n", strerror(errno)); //这里输出"onnection reset by peer"continue;    }    readbuffer[readsize] = '\0';      tick = time(NULL); //获取时间            snprintf(timebuffer, sizeof(timebuffer), "time : %.24s\r\n", ctime(&tick));    strcat(readbuffer, timebuffer);  //时间与客户数据连接到一起        write(connfd, readbuffer, strlen(readbuffer));  //发送给客户端}//printf("close the connfd\n");//fflush(stdout);close(connfd);    }};int main(int argc, char *argv[]){    if(argc != 2)    {printf("uasge : %s port", argv[0]);exit(-1);    }    int sockfd, connfd;    struct sockaddr_in serv_addr, cli_addr;    int port = atoi(argv[1]);    //初始化sockaddr_in    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(port);    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //允许任何人连接    //创建套接字    sockfd = socket(AF_INET, SOCK_STREAM, 0);    if(sockfd < 0)    {printf("socket error' n");exit(-1);    }    //绑定    bind(sockfd, (SSA *)&serv_addr, sizeof(serv_addr));    //监听套接字    listen(sockfd, 6);    //创建线程池    threadpool<task> pool(60, 100);    pool.start();  //开启线程池    while(1)    {socklen_t len = sizeof(cli_addr);connfd = accept(sockfd, (SSA *)&cli_addr, &len);  //接受连接task *ta = new task(connfd);   //新建任务char buf[20];printf("IP %s conn\n", inet_ntop(AF_INET, &cli_addr.sin_addr, buf, sizeof(buf)));     while(!pool.append_task(ta))  //添加任务到任务队列    printf("loop\n"); //测试用    }    return 0;}

下面的是客户端的代码:

#include <stdio.h>#include <sys/socket.h>#include <arpa/inet.h>#include <string.h>#include <sys/types.h>#include <unistd.h>#include <netinet/in.h>#include <stdlib.h>int main(int argc, char *argv[]){    if(argc != 3) //参数不对,退出    {printf("usage: %s ip port\n", argv[0]);exit(-1);    }    int sockfd;    struct sockaddr_in serv_addr;    int port = atoi(argv[2]);  //将字符串的端口转换称int    //初始化服务端的端口和IP地址    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(port);  //将主机字节序转换称网络字节序    inet_pton(AF_INET, argv[1], &serv_addr.sin_addr);    //创建套接字    sockfd = socket(AF_INET, SOCK_STREAM, 0);    //连接    connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));    char buffer[50];    write(sockfd, "hello\n", 6);  //写数据    shutdown(sockfd, SHUT_WR);  //解释在下面    size_t num = read(sockfd, buffer, sizeof(buffer));  //读数据    buffer[num] = '\0';    printf("read: %s\n", buffer);    shutdown(sockfd, SHUT_RD);//    close(sockfd);    return 0;}

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

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

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

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

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


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

#!/bin/bashfor i in `seq 2000` do    ./client.out 127.0.0.1 8989done

循环 执行2000次。

第二个shell文件:

#!/bin/bash./loop.sh > file1 &./loop.sh > file2 &./loop.sh > file3 &./loop.sh > file4 &./loop.sh > file5 &wait
开启5个进程来返问。

执行第二个shell文件

最终,耗时为:

real0m7.589suser0m0.460ssys0m1.944s

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


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



 

0 0