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;
}

 

 

 

 

 

原文地址:https://www.cnblogs.com/kongweisi/p/14129757.html