一个简单的echo服务器


前言;
本教程 基于linux,需要读者有系统编程的基础


公共部分

异常处理远远大于你的程序代码 本身

void errif(bool condition,const char* errmsg) {
    
    
    if(condition) {
    
    
        perror(errmsg);
        exit(EXIT_FAILURE);
    }
}

perror 为一个错误处理函数,输出到stdout

服务端

//绑定socket部分
 int sockfd=socket(AF_INET,SOCK_STREAM,0);//自动选协议
    errif(sockfd==-1,"create socket error");

    struct sockaddr_in serv_addr;
    serv_addr.sin_addr.s_addr=INADDR_ANY;
    serv_addr.sin_family=AF_INET;
    serv_addr.sin_port=htons(8080);

    errif(bind(sockfd,(sockaddr*)&serv_addr,sizeof(serv_addr)),"socket bind error");
    errif(listen(sockfd,SOMAXCONN),"socket listen error");

讲一下
宏 INADDR_ANY 为0.0.0.0 就是可以监听所有IP地址
宏 SOMAXCONN为系统建议最大连接数

//连接部分
struct sockaddr_in clnt_addr;
socklen_t clnt_socklen=sizeof(clnt_addr);
int clnt_fd=accept(sockfd,(sockaddr*)&clnt_addr,&clnt_socklen);
    printf("new client fd %d! IP: %s Port: %d\n", clnt_fd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));

这个无疑连接
注意 accept为阻塞函数,即是要等待连接 要不然printf的打印部分出不来

//业务部分
while(true) {
    
    
        char buf[READ_BUF];
        bzero(&buf,sizeof(buf));

        size_t read_bytes=read(clnt_fd,buf,sizeof(buf));

        if(read_bytes>0) {
    
    
            printf("message from %d : %s\n",clnt_fd,buf);
            write(clnt_fd,buf,sizeof(buf));
        }
        else if(read_bytes==0) {
    
    
          printf("client fd %d disconnected\n", clnt_fd);
          close(clnt_fd);
          break;
            
        }
        else if (read_bytes == -1)
        {
    
    
            close(clnt_fd);
            errif(true, "socket read error");
        }

    }

read和write是系统函数(linux系统 即是跨平台不强)
先读后写 关系连接

read:
返回值 > 0:表示成功读取的字节数。例如,返回值为 10,表示成功读取了 10 个字节。
返回值 = 0:表示已经到达文件末尾(EOF),没有更多数据可读。这通常发生在读取文件时,文件内容已经全部读完。
返回值 < 0:表示读取操作失败。此时,errno 会被设置为相应的错误码,可以
通过 write同理

错误码表格
以下是将这些错误码及其描述整理成的 Markdown 表格:

错误码 值 (具体值可能因系统而异) 描述
EINTR 通常为 4 写入操作被信号中断
EAGAIN 通常为 11 在非阻塞模式下,无法写入数据
EWOULDBLOCK 通常与 EAGAIN 相同 在非阻塞模式下,无法写入数据
EFAULT 通常为 14 缓冲区指针无效
EBADF 通常为 9 文件描述符无效
ENOSPC 通常为 28 磁盘空间不足

客户端

//连接部分
  int sockfd=socket(AF_INET,SOCK_STREAM,0);
    errif(sockfd==-1,"create socket error");

    struct sockaddr_in clnt_addr;
    clnt_addr.sin_family=AF_INET;
    clnt_addr.sin_port=htons(8080);
    clnt_addr.sin_addr.s_addr=inet_addr("127.0.0.1");

    errif(connect(sockfd,(sockaddr*)&clnt_addr,sizeof(clnt_addr))==-1,"socket connect error");

客户端 没有所谓 bind和监听

//业务部分
        char buf[1024];
        bzero(&buf,sizeof(buf));
        scanf("%s",buf);
        size_t write_bytes=write(sockfd,buf,sizeof(buf));
        if (write_bytes == -1) {
    
    
            printf("Socket already disconnected, can't write any more!\n");
            break;
        }

        ssize_t read_bytes = read(sockfd, buf, sizeof(buf));
        if (read_bytes > 0) {
    
    
            printf("Message from server: %s\n", buf);
        } else if (read_bytes == 0) {
    
    
            printf("Server socket disconnected!\n");
            break;
        }else if(read_bytes == -1){
    
    
            close(sockfd);
            errif(true, "socket read error");
        }

先写后读 服务器断开

** 运行命令**

扫描二维码关注公众号,回复: 17545055 查看本文章

g++ server.cpp -o server
g++ client.cpp -o client

分别再不同的终端 ./ server . /client