C语言笔记-25-网络-TCP网络编程

C语言笔记-25-网络-TCP网络编程



前言

自学笔记,没有历史知识铺垫(省略百度部分)C语言笔记-25-网络-TCP网络编程


一、TCP编程模型概括

服务器端编程模型

  1. socket() 创建socket设备,获取该设备的文件描述符 sfd
  2. bind()将sfd与本地ip、端口绑定
  3. listen()设置sfd为被动状态,当客户端请求到达时,将请求存放到sfd设备的未决连接队列
  4. accept()从sfd设备未决连接队列中取出请求,返回该请求的连接描述符
  5. read()使用连接描述符,获取请求信息
  6. do Some...处理请求信息
  7. write()将处理结果通过连接描述符返回给请求客户端
  8. close()关闭连接描述符,结束通讯

客户端编程模型

  1. socket() 创建socket设备,获取该设备文件描述符 cfd
  2. connect()使用cfd向服务器端发起连接
  3. write()向服务器发送信息
  4. read()阻塞等待服务器响应
  5. do Some...处理服务器响应信息
  6. close()关闭本次连接,结束通讯

二、inet工具

htonl

在主机和网络字节顺序之间转换值,对齐时使用,如输入ip、端口时
h 代表 host
to – 转换至
n 代表 net
l代表long
s代表short

     #include <arpa/inet.h>
     
     uint64_t htonll(uint64_t hostlonglong);
     uint32_t htonl(uint32_t hostlong);
     uint16_t htons(uint16_t hostshort);
     uint64_t ntohll(uint64_t netlonglong);
     uint32_t ntohl(uint32_t netlong);
     uint16_t ntohs(uint16_t netshort);

inet_pton

将字符串地址与二进制网络地址相互转化

#include <arpa/inet.h>
// 将字符串地址转为二进制网络地址
int inet_pton(int af, const char * restrict src, void * restrict dst);
// 将二进制网络地址转为字符串地址
const char * inet_ntop(int af, const void * restrict src, char * restrict dst, socklen_t size);

三、TCP编程模型代码

TCP服务端

#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    printf("服务器端启动中...\n");

    // 使用sockaddr_in 替换 sockaddr
    struct sockaddr_in server_addr;
    // 家族簇
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8089);
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // 1. 创建socket设备
    /*
     *   TODO 地址家族
     *      PF_LOCAL        Host-internal protocols, formerly called PF_UNIX,
     *      PF_UNIX         Host-internal protocols, deprecated, use PF_LOCAL,
     *      PF_INET         Internet version 4 protocols,
     *      PF_ROUTE        Internal Routing protocol,
     *      PF_KEY          Internal key-management function,
     *      PF_INET6        Internet version 6 protocols,
     *      PF_SYSTEM       System domain,
     *      PF_NDRV         Raw access to network device,
     *      PF_VSOCK        VM Sockets protocols
     *
     *   TODO 套接字类型
     *      SOCK_STREAM     TCP
     *      SOCK_DGRAM      UDP
     *      SOCK_RAW        UDP
     */
    int sfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sfd == -1)
    {
        perror("创建socket设备失败");
    }

    // 2. 绑定socket设备到ip、端口
    /*
     * TODO 通用地址结构
     * struct sockaddr {
     * 	__uint8_t       sa_len;         // total length
     * 	sa_family_t     sa_family;      // [XSI] address family
     * 	char            sa_data[14];    // [XSI] addr value (actually larger)
     * };
     *
     * TODO IPV4 具体地址结构(创建时建议使用具体地址结构 强转位通用地址结构即可)
     * struct sockaddr_in {
     *   sa_family_t    sin_family; // address family: AF_INET
     *   in_port_t      sin_port; // port in network byte order
     *   struct in_addr sin_addr;  // internet address
     * };
     */
    int bindResult = bind(sfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (bindResult == -1)
    {
        perror("绑定socket设备失败");
    }

    // 3. 监听客户端消息到 链接未决队列
    int listenResult = listen(sfd, 10);
    if (listenResult == -1)
    {
        perror("监听socket设备失败");
    }

    printf("服务器端启动成功,开始监听客户端消息...\n");

    char buf[128];
    while (1)
    {
        // 4. 读取 链接未决队列请求 返回客户端链接未决描述符
        int acceptResult = accept(sfd, NULL, NULL);
        if (acceptResult == -1)
        {
            perror("接收客户端消息失败");
        }
        // 5. 读取客户端消息
        int r = read(acceptResult, buf, 128);
        // 6. 处理客户端消息,返回给客户端
        write(acceptResult, buf, r);
        write(1, buf, r);
        // 7. 关闭本次客户端链接
        close(acceptResult);
    }

    return 0;
}

// 启动执行结果
dony15$ ./server_socket 
服务器端启动中...
服务器端启动成功,开始监听客户端消息...
Send Data

TCP客户端


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

int main(int argc, char *argv[])
{
    char *msg = "Send Data\n";
    char buf[128];
    printf("客户端启动中...\n");

    struct sockaddr_in client_addr;
    client_addr.sin_family = AF_INET;
    client_addr.sin_port = htons(8089);
    client_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    inet_pton(AF_INET, argv[1], &client_addr.sin_addr);

    int cfd = socket(PF_INET, SOCK_STREAM, 0);
    if (cfd == -1)
    {
        perror("创建socket设备失败");
    }

    int connectResult = connect(cfd, (struct sockaddr *)&client_addr, sizeof(client_addr));
    if (connectResult == -1)
    {
        perror("连接服务器失败");
    }

    int writeResult = write(cfd, msg, strlen(msg) + 1);
    if (writeResult == -1)
    {
        perror("向服务器发送数据失败");
    }

    int r = read(cfd, buf, 128);
    write(1, buf, r);
    close(cfd);
    printf("\n客户端运行结束\n");

    return 0;
}

// 启动执行结果
dony15$ ./client_socket 127.0.0.1
客户端启动中...
创建socket设备成功
连接服务器成功
Send Data

客户端运行结束

总结

本章主要为C语言笔记-25-网络-TCP网络编程

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值