当前位置: 首页 > news >正文

UNIX网络编程学习记录2-第一章

标题遵循原书标题

1.2、获取时间的客户端程序

#include "unp.h"    /*原书自己写的头文件,该头文件包含了网络编程需要的大部分系统头文件,还定义了一些常量如MAXLINE */

int main(int argc, char** argv){ /* argc表示入参个数,argv接收入参*/
    /* 变量定义 */
    int sockfd, n;
    char recvline(MAXLINE + 1);
    struct sockaddr_in servaddr;

    if (argc != 2) {
        err_quit("uage: a.out <IPaddress>");
    }
    
    /* 
    socket函数创建一个AF_INET(IPv4)的字节流套接字
    该函数返回一个整形数值,该返回值被赋给了sockfd变量
    */
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        err_sys("socket error");
    }
    
    /* 清空结构体servaddr */
    bzero(&servaddr, sizeof(servaddr));

    /* 
    设置该套接字的地址族是IPv4
    端口号:13是时间服务器众所周知的端口
    套接字结构体中的ip和端口必须是特定格式,所以13要用库函数hton转换
    */
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(13);

    /* 
    库函数onet_pton用来把点分十进制的ipv4地址转换为二进制
    第一个参数是地址族
    第二个参数是点分十进制ip地址
    第三个参数是存储转换结果的地址
    */
    if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
        err_quit("inet_pton error for %S", argv[1]);
    }

    /* 
    库函数connet用于与服务器段建立连接,
    第一个参数是客户端套接字
    第二个参数是指定服务器地址的结构体指针
    第三个参数是地址结构体的长度
    */
    if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) < 0) {
        err_sys("connect error");
    }

    /* 
    read函数循环读取服务器返回的结果
    用标准IO函数fputs输出结果
    */
    
    while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
        recvline[n] = 0;
        if (fputs(recvline, stdout) == EOF) {
            err_sys("fputs error");
        }
    }

    if (n < 0) {
        err_sys("read error");
    }
    
    /* 
    结束程序
    */
    exit(0);

}

1.4、包裹函数

简单说,包裹函数就包含了库函数的异常和错误处理逻辑,一般地,包裹函数的命名是库函数首字母大写。

以socket函数为例:

sockfd = socket(AF_INET, SOCK_STREAM, 0);

他的包裹函数:

int Socket(int family, int type, int protocol) {
    int n;
    if ((n = socket(family, type, protocol)) < 0) {
        sys_error("socket error");
    }
    return n;
}

1.5、获取时间的服务端程序

#include "unp.h"
#include <time.h>

int main(int argc, char** argv) {
    int listenfd, connfd;
    struct sockaddr_in servaddr;
    char buff[MAXLINE];
    time_t ticks;

    listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    
    bzero(&servaddr, sizeof(servaddr));

    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = hton(13);

    Bind(listenfd, (SA*)&servaddr, sizeof(servaddr));

    Listen(listenfd, LISTENQ);

    for(; ;) {
        connfd = Accept(listenfd, (SA*)NULL, NULL);
        ticks = time(NULL);

        snprint(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff));

        Close(connfd);
    }
}

注:服务器端代码不过多注释,建议编码时用snprint代替sprintf,因为前者可以检查缓存区是否溢出。此外还有用fgets、strncat、ctrncpy  代替gets、strcat、strcpy

相关文章:

  • Centos 7安装docker
  • 网络安全-攻击流程-应用层
  • 五十天精通硬件设计第32天-S参数
  • DeepSeek在linux下的安装部署与应用测试
  • GPU(Graphics Processing Unit)详解
  • STM32的HAL库开发---ADC
  • Deepseek PHP API调用指南
  • 蓝桥杯篇---IAP15F2K61S2串口
  • STM32的启动流程
  • 基于STM32的智能路灯节能控制系统
  • 【设计模式】01- 一文理解常用设计模式-“创建型模式”篇
  • vue3 分析总结响应式丢失问题原因(二)
  • 【从0做项目】Java搜索引擎(3)
  • 使用 DeepSeek 生成商城流程图
  • Rasa学习笔记
  • 基于HAL库的按钮实验
  • 【个人开发】deepspeed+Llama-factory 本地数据多卡Lora微调
  • 【AI战略思考15】我对做自媒体视频博主的初步探索和一些思考
  • ubuntu下ollama/vllm两种方式在本地部署Deepseek-R1
  • 数据结构 堆和priority_queue
  • 陈平评《艺术科学的目的与界限》|现代艺术史学的奠基时代
  • 永辉超市一季度净利降近八成,未来12个月至18个月是改革成果集中释放期
  • 弘扬 “上海精神”,上合组织政党论坛聚焦政党责任与使命
  • 夜读丨囿于厨房与爱
  • 政治局会议:要提高中低收入群体收入,设立服务消费与养老再贷款
  • 中越海警2025年第一次北部湾联合巡逻圆满结束