zoukankan      html  css  js  c++  java
  • 01--c实现基础客户端和服务端与c++ boost.asio实现对比

    c实现服务端和客户端交互:

    学习查阅的博客:

    https://blog.csdn.net/u011068702/article/details/54380259

    https://blog.csdn.net/iamhycljc/article/details/6859013

    在Terminator中的快捷键,alt+a锁定多个,alt+o取消锁定

    c语言中,printf("...... ");  一定要加 !!!!!!

    编译的时候,加上-Wall -g  前者可以打印错误或警告信息,后者可以用gdb调试

     

     

     

    服务端 server.c:

    调试方法,在命令行输入:nc 127.0.0.1 port

    ///c
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <stdlib.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <ctype.h>
    #include <strings.h>
    
    
    #define SERV_IP "127.0.0.1"//点分十进制类型
    #define SERV_PORT 6666//服务端port,不能大于65535(2的16次方),1000以下的端口一般给系统使用,一般3000以上
    
    ///服务端代码:socket --> bind --> listen --> accept --> (read write) --> close两个socket
    
    int main(void)
    {
        int sfd;//用来建立连接的文件描述符
        struct sockaddr_in serv_addr;//存储客户端的ip、port
        struct sockaddr_in client_addr;
        int cfd;//用来和客户端通信的文件描述符   记住,socket都是成对出现的
        socklen_t client_addr_len;//listen的传入传出参数
        char buf[BUFSIZ];//BUFSIZ 操作系统自带的宏,8K大小
        char client_IP[BUFSIZ];
        int n;//read 实际读到的字节
    
        //查看方式:linux命令行, man socket
        //三个参数: int socket(int domain, int type, int protocol);
        //domain: 即地址类型,ipv4或ipv6,即AF_INET或AF_INET6
        //type: 用来建立连接的方式,即tcp(默认)或udp
        //protocol: 0
        sfd = socket(AF_INET, SOCK_STREAM, 0);
        //TODO 检测sfd返回值
    
    
        bzero(&serv_addr, sizeof(serv_addr));//使用serv_addr之前,先初始化,即清空  和memset不同在于,memset可以初始化到任意数值
        serv_addr.sin_family = AF_INET;//作用域(类型):ipv4、ipv6、本地套接字 等
        serv_addr.sin_port = htons(SERV_PORT);//注意:默认是小端存储,要把本地字节序,转化成网络字节序  int--->二进制0101
        //serv_addr.sin_addr.s_addr = inet_pton(SERV_IP);//注意:同理  #include <arpa/inet.h>      字符串--->二进制0101
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);//区别,一个是int转,一个是字符串转
        //serv_addr.sin_addr.s_addr = inet_addr(SERV_IP);//INADDR_ANY就是inet_addr("0.0.0.0")
        bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
        //std::cout << sizeof(serv_addr) << std::endl;
    
    
        listen(sfd, 128);//参数2:允许最大上限的客户端同时请求连接数
    
    
        client_addr_len = sizeof(client_addr);
        cfd = accept(sfd, (struct sockaddr *)&client_addr, &client_addr_len);//等待客户端连接  阻塞等待
        printf("client IP:%s, client port:%d
    ",
               inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, client_IP, sizeof(client_IP)),
               ntohs(client_addr.sin_port));
    
    
        while(1){
            n = read(cfd, buf, sizeof(buf));//从cfd中读,读到的数据都在buf缓存中  n:实际读到的字节
            for (int i = 0; i < n; ++i) {
                buf[i] = toupper(buf[i]);//小写转大写
            }
            write(cfd, buf, n);
        }
    
    
        close(sfd);
        close(cfd);
    
    
        return 0;
    }

    客户端 client.c:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <string.h>
    
    
    #define SERV_IP "127.0.0.1"
    #define SERV_PORT 6666
    
    int main(void)
    {
        int cfd;
        struct sockaddr_in serv_addr;//这里存的是服务端的ip和port,因为是connect的参数
        socklen_t serv_addr_len;
        char buf[BUFSIZ];
        int n;//读到的字节数
    
        cfd = socket(AF_INET, SOCK_STREAM, 0);//ipv4,流式协议
    
    
        //linux会随机分配ip给客户端,因此可以不bind
    
    
        memset(&serv_addr, 0, sizeof(serv_addr));//初始化,防止ip的初始值是乱七八糟的   memset:将指针*转换成int
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(SERV_PORT);//大端转小端
        //ip:serv_addr.sin_addr.s_addr = inet_addr(SERV_IP);
        inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);
        connect(cfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    
    
        /*在C语言中有strlen和sizeof两个函数求字符数组的长度函数,他们俩的区别就是是否把最后的结束标志也加上去。
        strlen是不加的,他表示字符串的长度。
        而sizeof求的是字符串在内存中的长度,所以它是加上最后的''的
        所以一般而言后者的长度会比前者多1。*/
        while (1){
            fgets(buf, sizeof(buf), stdin);//类似c++ 中的cin <<  将用户的输入写入到buf中  fgets:用户输入hello world  --> hello world
    
            write(cfd, buf, strlen(buf));
            n = read(cfd, buf, sizeof(buf));
            write(STDOUT_FILENO, buf, n);//写到屏幕上去
        }
    
    
        close(cfd);
    
        return 0;
    }

    boost::asio实现服务端和客户端交互:

     为cmakelists.txt添加boost组件:https://www.cnblogs.com/magic-428/p/9144492.html

    boost::asio的同步和异步方式:https://www.cnblogs.com/lidabo/p/8317196.html 

    写好的代码编译的时候,一定要加上 -lboost_system   比如:/usr/bin/g++ main.cpp -o test_main -Wall -g -lboost_system

    cmakelists.txt(为了在clion中写代码有代码提示)文件写法例如:

    cmake_minimum_required(VERSION 2.8)
    project( process )
    
    SET(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++11")
    find_package(Boost REQUIRED COMPONENTS
            # regex
            filesystem   # 我的工程中只使用了 boost 的 filesystem 功能,因此这里只有一个组件
            system
            )
    if(NOT Boost_FOUND)
        message("Not found Boost")
    endif()
    
    include_directories(${Boost_INCLUDE_DIRS})
    message("${Boost_INCLUDE_DIRS}")
    message("${Boost_LIBRARIES}")
    
    add_executable( 01_test main.cpp)
    target_link_libraries(01_test ${Boost_LIBRARIES})

    运行报错,正好学习分析一下,linux下的core dumped这种错误,主要学习,ulimit命令和 gdb <program> core 来调试:

    https://www.cnblogs.com/s-lisheng/p/11278193.html

    同步方式实现的服务端和客户端:

    服务端:

    #include <iostream>
    #include <boost/asio.hpp>
    
    using namespace boost::asio;
    
    int main(int argc, char* argv[])
    {
        // 所有asio类都需要io_service对象
        io_service iosev;
        ip::tcp::acceptor acceptor(iosev,
                                   ip::tcp::endpoint(ip::tcp::v4(), 6667));//todo 尽量使用3000以上的端口!!!
    
    
    
        for(;;)
        {
            // socket对象
            ip::tcp::socket socket(iosev);
            // 等待直到客户端连接进来
            acceptor.accept(socket);
            // 显示连接进来的客户端
            std::cout << socket.remote_endpoint().address() << std::endl;
            //std::cout << socket.remote_endpoint().data() << std::endl;
    
            // 向客户端发送hello world!
            boost::system::error_code ec;
            socket.write_some(buffer("hello world!"), ec);
            // 如果出错,打印出错信息
            if(ec)
            {
                std::cout << boost::system::system_error(ec).what() << std::endl;
                break;
            }
            // 与当前客户交互完成后循环继续等待下一客户连接
        }
        return 0;
    }

    客户端:

    #include <iostream>
    #include <boost/asio.hpp>
    using namespace boost::asio;
    int main(int argc, char* argv[])
    {
        // 所有asio类都需要io_service对象
        io_service iosev;
        // socket对象
        ip::tcp::socket socket(iosev);
        // 连接端点,这里使用了本机连接,可以修改IP地址测试远程连接
        ip::tcp::endpoint ep(ip::address_v4::from_string("127.0.0.1"), 6667);
        // 连接服务器
        boost::system::error_code ec;
        socket.connect(ep,ec);
        // 如果出错,打印出错信息
        if(ec)
        {
            std::cout << boost::system::system_error(ec).what() << std::endl;
            return -1;
        }
        // 接收数据
        char buf[100];
        size_t len=socket.read_some(buffer(buf), ec);
    //    std::cout.write(buf, len);
        std::cout.write(buf, len);
        std::cout << std::endl;
        return 0;
    }

     

     

     

     

     

  • 相关阅读:
    Python pydoc.py
    Python dir
    HTTPS Web配置举例
    Kubernetes 笔记 03 扫清概念
    一文总结 Linux 虚拟网络设备 eth, tap/tun, veth-pair
    一文掌握 Linux 性能分析之内存篇
    云计算底层技术之高性能集群
    利用 Linux tap/tun 虚拟设备写一个 ICMP echo 程序
    Linux 网络工具详解之 ip tuntap 和 tunctl 创建 tap/tun 设备
    [原创] 详解云计算网络底层技术——虚拟网络设备 tap/tun 原理解析
  • 原文地址:https://www.cnblogs.com/kongweisi/p/14129757.html
Copyright © 2011-2022 走看看