在ubuntu+vs code上通过HTTP协议实现服务器端和客户端通信(转载)

2023-05-16

转载自:在ubuntu+vs code上通过HTTP协议实现服务器端和客户端通信_DP323的博客-CSDN博客


ubuntu+vs code上通过HTTP协议实现服务器端和客户端通信

DP323 2021-06-07 15:47:47

52  正在上传…重新上传取消​ 收藏 

分类专栏: Linux 文章标签:

http通信 vs code 服务器端 客户端 下载并保存数据

版权

​ Linux  专栏收录该内容

11 篇文章 0 订阅

订阅专栏

一、操作系统: Ubuntu16.0.4(两台虚拟机)

二、编译工具:vs code(相关配置见之前的文章vs code安装与配置,在搜索C++配件时,可能有些组件必须添加上,不然程序编译会报错,缺少一些库)

三、服务器端实现功能:

1、开启服务器端,一直侦听服务器端口(8000);

2、接受客户端请求,控制台打印响应报文,响应报文由状态行、响应头部、空行、数据体4个部分组成;

3、读取请求并发送文件,发送完一次数据后关闭连接,若客户端需要循环从服务器下载数据,客户端需要循环连接服务器;

四、服务器端代码实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>


int main(int argc, char *argv[])
{
    unsigned short port = 8000;   //设置默认端口号
    if(argc > 1)
    {
        port = atoi(argv[1]);   //将参数2赋值给端口号变量
    }

    //创建TCP套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if( sockfd < 0)
    {
        perror("socket");   
        exit(-1);
    }

    //服务器套接字地址变量赋值
    struct sockaddr_in my_addr;
    bzero(&my_addr, sizeof(my_addr));
    my_addr.sin_family = AF_INET;   //IPV4族
    my_addr.sin_port   = htons(port); //将端口号转换成网络字节序
    my_addr.sin_addr.s_addr = htonl(INADDR_ANY); //本机IP地址

    //绑定TCP套接字
    if( bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)) != 0)
    {
        perror("bind");
        close(sockfd);      
        exit(-1);
    }

    //监听
    if( listen(sockfd, 10) != 0)
    {
        perror("listen");
        close(sockfd);      
        exit(-1);
    }

    printf("Listenning at port=%d\n",port);   //打印端口号信息
    //printf("Usage: http://127.0.0.1:%d/html/index.html\n", port);

    while(1)
    {
        char cli_ip[INET_ADDRSTRLEN] = {0};  //存放客户端点分十进制IP地址
        struct sockaddr_in client_addr;
        socklen_t cliaddr_len = sizeof(client_addr);

        //等待客户端连接
        int connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len);
        printf("connfd=%d\n",connfd); //打印已连接套接字
        if(connfd > 0)
        {
            if(fork() == 0)  //创建进程并判断返回值
            {
                close(sockfd);
                //子进程执行
                int  fd = 0;
                int  len = 0;
                char buf[1024] = "";
                char filename[50] = "";

                //将网络字节序转换成点分十进制形式存放在cli_ip中
                inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);
                printf("connected form %s\n\r", cli_ip);   //打印点分十进制形式的客户端IP地址
                recv(connfd, buf, sizeof(buf), 0);   //接收客户端发送的请求内容
                sscanf(buf, "GET /%[^ ]", filename);   //解析客户端发送请求字符串
                printf("filename=*%s*\n", filename);

                fd = open(filename, O_RDONLY);   //以只读方式打开文件
                if( fd < 0)   //如果打开文件失败
                {
                    //HTTP失败头部
                    char err[]= "HTTP/1.1 404 Not Found\r\n"
                                "Content-Type: text/html\r\n"
                                "\r\n"  
                                "<HTML><BODY>File not found</BODY></HTML>";

                    perror("open error");                   
                    send(connfd, err, strlen(err), 0);
                    close(connfd);  //关闭已连接套接字
                    exit(0);    //子进程退出
                }

                //打开文件成功后
                //接收成功时返回的头部
                char head[]="HTTP/1.1 200 OK\r\n"
                            "Content-Type: text/html\r\n"
                            "\r\n";
                send(connfd, head, strlen(head), 0);  //发送HTTP请求成功头部

                while( (len = read(fd, buf, sizeof(buf))) > 0)   //循环读取文件内容
                {
                    send(connfd, buf, len, 0);       //将读得的数据发送给客户端
                }

                close(fd);   //成功后关闭文件
                close(connfd);   //关闭已连接套接字,这样的话,完成一次数据传输后就关闭了连接,并非keep-alive!
                exit(0);     //子进程退出
            }
        }   

        close(connfd);   //父进程关闭连接套接字
    }
    close(sockfd);
    printf("exit main!\n");

    return 0;
}

五、客户端实现功能

1、创建通信端点:套接字

2、设置服务器地址结构体

3、主动连接服务器

4、编写http请求报文包,并发送到服务器端

5、获取http响应报文

6、下载指定的服务器端文件

六、客户端代码实现

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>                         
#include <unistd.h>  
#include <fcntl.h>
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>
#include <time.h>



int main()
{
    while(1)   //这里是为了让服务器循环发送数据,因为服务器端发送完一次数据会关闭连接,所以循环 
               //while(1)要从建立连接开始
   { 
     // 创建通信端点:套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);  
    printf("creat socket\r\n");
    // 设置服务器地址结构体  
    struct sockaddr_in server_addr;  
    bzero(&server_addr,sizeof(server_addr)); // 初始化服务器地址  
    server_addr.sin_family = AF_INET;   // IPv4  
    server_addr.sin_port = htons(8000); // nginx服务器监听的端口 
    inet_pton(AF_INET, "192.168.254.33", &server_addr.sin_addr);   // 服务器ip  
    printf("server addr has ready\r\n");
     // 主动连接服务器  
     int bytes_received=0;
    int filesaved=0;  
    
    int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));  
    if(err_log != 0)  
    {  
        perror("connect"); 
         printf("connect has error\r\n");
        close(sockfd);  
        return -1;  
    }
    else{
        printf("connect has ready\r\n");
    }
    
    //http请求报文包
    char send_buf[] = 
        "GET /GetRoundData.html HTTP/1.1\r\n"
        "Accept: text/html,image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, application/x-ms-xbap, */*\r\n"
        "Accept-Language: zh-Hans-CN,zh-Hans;q=0.8,en-US;q=0.5,en;q=0.3\r\n"
        "User-Agent: Mozilla/5.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)\r\n"
        "Accept-Encoding: gzip, deflate\r\n"
        "Host: 192.168.254.66:8000\r\n"
        "Connection: Keep-Alive\r\n"
        "\r\n";

    
    //发送http请求报文包

    
    send(sockfd, send_buf, sizeof(send_buf)-1, 0);
    printf("message has send\r\n");
    
    //
    //int contentlengh=0;      
    //获取http响应报文
    char recv_buf[8*1024] = {0};  //recv_buf是响应信息(包括响应头部和数据体),返回值是保存的字节数
    printf("err_log=%d\n\r",err_log);
    bytes_received=recv(sockfd, recv_buf, sizeof(recv_buf), 0);

    printf("bytes_received=%d\r\n",bytes_received);
    //在指定位置存储服务器上文件/index.html,并在控制台打印文件内容
    //int byteRec=bytes_received-44;
    //if((byteRec))
    //{

    //将服务器文件存储到客户端指定位置
    FILE* fd=fopen("GetRoundData.json","wb+");
    
    //int filesaved=fwrite(recv_buf,sizeof(recv_buf),1,fd);
    filesaved=fwrite(recv_buf,1,bytes_received,fd);
    printf("filesaved=%d",filesaved);
    fclose(fd);
    
    sleep(2);   // 等待2秒后再次发送连接请求 

    }

    //else{
       
        //printf("data is null!!!!\n\r");
        //sleep(2);
        
    //}

      
    return 0;

}

七、程序运行过程和结果

1、首先运行服务器端,显示在监听端口8000,看是否有客户端发出连接请求

2、运行客户端,循环发送请求,循环显示信息

3、在服务器端,控制台输出信息

至此,只要服务器端一直运行,客户端可以多次连接服务器端获取服务器上的文件,并下载保存数据在客户端

目前仍存在一些问题:

1、有些不稳定,第一次没有打印出文件内容,原因待查

2、保存的文件包含有头部,该如何去除

3、若有多个应用需要访问服务器,如何用多线程来实现对服务器端的访问;

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在ubuntu+vs code上通过HTTP协议实现服务器端和客户端通信(转载) 的相关文章

随机推荐