Linux学习——TCP

一.TCP编程API

1.socket函数

1.socket函数

include include

int socket(int domain,int type,int protocol);

参数

domain

AF_INET

AF_INET6

AF_UNIX,AF_LOCAL

AF_NETLINK

AF_PACKET

type

SOCK_STREAM: 流式套接字,唯一对应于TCP

SOCK_DGRAM:数据报套接字,唯一对应着UDP

SOCK_RAW:原始套接字

protocol

一般填0,原始套接字编程时需填充

返回值

成功返回文件描述符

出错返回-1

如果是IPV6编程,要使用struct sockddr_in6结构体(man 7 IPV6),通常使用struct

sockaddr_storage来编程。

复制代码
int socket(int domain,int type,int protocol);
    参数
        domain
        AF_INET
        AF_INET6
        AF_UNIX,AF_LOCAL
        AF_NETLINK
        AF_PACKET
    type
        SOCK_STREAM: 流式套接字,唯一对应于TCP
        SOCK_DGRAM:数据报套接字,唯一对应着UDP
        SOCK_RAW:原始套接字
    protocol
        一般填0,原始套接字编程时需填充
    返回值
        成功返回文件描述符
        出错返回-1
        如果是IPV6编程,要使用struct sockddr_in6结构体(man 7 IPV6),通常使用struct                        
        sockaddr_storage来编程。

2.bind函数

2.bind函数

int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)

参数

sockfd:通过socket()函数拿到的fd

addr:采用struct sockaddr的结构体地址,通用结构体

struct sockaddr

{

sa_family_t sa_family;

char sa_data4;

}

struct sockaddr_in{ 基于Internel通信结构体

as_family_t sin_family;

in_port_t sin_port;

struct in_addr sin_addr;

sin_zero , //填充字节,需清零

}

struct in_addr{

uint32_t s_addr;

}

addrlen:地址长度

复制代码
2.bind函数
int bind(int sockfd,const struct sockaddr *addr,socklen_t addrlen)
    参数
        sockfd:通过socket()函数拿到的fd
        addr:采用struct sockaddr的结构体地址,通用结构体
        struct sockaddr
         {
            sa_family_t sa_family;
            char sa_data[4];
         }
        struct sockaddr_in{ 基于Internel通信结构体
            as_family_t sin_family;
            in_port_t sin_port;
            struct in_addr sin_addr;
            sin_zero , //填充字节,需清零
            }
        struct in_addr{
            uint32_t s_addr;
            }
        addrlen:地址长度

3.listen函数

3.listen()函数
int listen(int sockfd,int backlog);
参数:
sockfd: 通过socket()函数拿到的fd;
backLog:同时允许几路客户端和服务器进行正在连接的过程(正在三次握手),一般填5。
内核中服务器的套接字fd会维护2个链表
1.正在三次握手的客户端链表(数量=2*backlog+1)
2.已经建立好连接的客户端链表(已经完成三次握手分配好了的newfd)
返回值:
成功返回0
出错返回-1
listen(fd,5);//表示系统允许11(2*5+1)个客户端同时进行三次握手

复制代码
3.listen()函数
int listen(int sockfd,int backlog);
    参数:
        sockfd: 通过socket()函数拿到的fd;
        backLog:同时允许几路客户端和服务器进行正在连接的过程(正在三次握手),一般填5。
            内核中服务器的套接字fd会维护2个链表
                1.正在三次握手的客户端链表(数量=2*backlog+1)
                2.已经建立好连接的客户端链表(已经完成三次握手分配好了的newfd)
        返回值:
                成功返回0
            出错返回-1
    listen(fd,5);//表示系统允许11(2*5+1)个客户端同时进行三次握手

4.accept函数

复制代码
4.accept()函数
阻塞等待客户端连接请求
    int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        参数
            sockfd:经过前面socket()创建并通过bind(),listen()设置过的fd
            addr:指向存放地址信息的结构体的首地址
                    获取客户端IP地址和端口号
            addrlen:存放地址信息的结构体的大小
    返回值
        成功,返回已经建立连接的新的newfd
        出错,返回-1

5.客户端连接函数connect

复制代码
5.客户端连接函数connect()
int connect (int sockfd, struct sockaddr * serv_addr, int addrlen)
    参数:
        sockfd:通过socket()函数拿到的fd
        addr:struct sockaddr的结构体变量地址
        addrlen:地址长度
    返回值:
        成功,返回0
        失败,返回-1

二.编程

socket函数编写

用将socket函数的返回值给fd,通过fd是否小于零来判断是否成功

bland函数

第一个参数是socket()拿到的fd

sockaddr_in 结构体

第二个参数是结构体,需先定义 sockaddr_in 结构体

定义之后在填充之前还需要将结构体清零 ,用bzero函数清零

清零之后去初始化结构体

man 2 bind 往下滑找到 socket,它是在man 7 ip,去man 7 ip 中找到我们填充的sockaddr_in结构体,发现它初始化用的是AF_INET

初始化之后去写结构体的第二个参数sin_port的ip地址,可以去宏定义,5000以前是内核相关的,为了防止冲突写5001

SERV_IP_ADDR通过ifconfig查看

sin_port用的是本地字节,需要转换成网络字节,用u_short htons(u_short short)主机字节序到网络字节序

结构体第三个参数

sin_addr 又指向s_addr,也是要转换成网络节字

sockaddr_in结构体也可以使用另一种方式初始化与配置

将sockaddr_in结构体转化成sockaddr结构体

bind函数成功返回0,失败返回-1

去判断是否成功

listen函数

accept函数

TCP服务器读取内容

接着上一章TCP学习所写的代码写 read函数代码

read成功返回字节数,失败返回-1

在do-while循环里不断读取accept函数接收到的数据,当小于-1就退出

后两个if作用是判断是否还在接收字节,没有就退出

第三个if 是客户端是否主动要退出如果是就退出

TCP客户端

三.代码优化

优化一

sin.sin_addr.s_addr = inet_addr(SERV_IP_ADDR)可以换成sin.sin_addr.s_addr =INADDR_ANY

就可以自动获取服务器地址,不用自己去写入

优化二

accept优化,通过accept获取客户端信息

之前accept的第二第三个参数都是不使用,现在使用

复制代码
4.accept()函数
阻塞等待客户端连接请求
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数
    sockfd:经过前面socket()创建并通过bind(),listen()设置过的fd
    addr:指向存放地址信息的结构体的首地址
    获取客户端IP地址和端口号
    addrlen:存放地址信息的结构体的大小
返回值
    成功,返回返回已经建立连接的新的newfd
    出错,返回-1

addr:指向存放地址信息的结构体的首地址,这个结构体是

structsockaddr_in { 基于Internel通信结构体

as_family_t sin_family;

in_port_t sin_port;

struct in_addr sin_addr;

sin_zero , //填充字节,需清零

}

两个机子通信是过程:本地字节序--->网络字节序--->本地字节序

这就需要用一些转换函数

我们是要获取IP地址,然后将其从本地转成网络/网络转本地所以使用下面这个函数

复制代码
inet_ntop(int af,const void *src,char *dst,socklen_t size)
    把ipv4和ipv6的网络字节序变成本地的字符串形式的IP地址

参数
    1.af:地址协议族(AF_INET或AF_INET6)
    2.src:是一个指针(32)
    3.dst:输出结果为32位点分形式的IP地址
    4.size:长度

成功返回非零,失败返回零

网络到主机,两个字节用ntonhs

IP地址一般都是16字节xxxx.xxxx.xxxx xxx 字符串加一个结束符所以16字节

10.0.2.15是ip地址,58220是端口号

相关推荐
一只小菜鸡..1 分钟前
南京大学 操作系统 (JYY) 学习笔记:Hello, OS World! (程序的机器视角)
java·笔记·学习
小此方6 分钟前
Re:Linux系统篇(四十六)信号篇·四:一文串联操作系统底层:时钟中断、内核态切换、系统调用与 Linux 信号处理全解析
linux·驱动开发·信号处理
lazy H1 小时前
从入门到日常开发,一篇文章掌握 Git 核心操作
git·后端·学习·github
无人生还别怕1 小时前
如何制作一个linux标准iso镜像
linux·iso·opencloudos·openanolisos
Yana.nice9 小时前
Linux 只保留 30 天内日志(find命令删除日志文件)
linux·运维·chrome
a11177612 小时前
2FA 验证码生成器(github登录验证 app)
笔记·学习
我的xiaodoujiao12 小时前
API 接口自动化测试详细图文教程学习系列32--Allure测试报告2
python·学习·测试工具·pytest
DFT计算杂谈13 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
Zhang~Ling14 小时前
从 fopen 到 struct file:从零开始拆解 Linux 文件 I/O
linux·运维·服务器
DeeplyMind14 小时前
Linux 深入 per-VMA lock:Linux 缺页路径如何摆脱 mmap_lock
linux·per-vma lock