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_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:地址长度

复制代码
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是端口号

相关推荐
武子康37 分钟前
Java-82 深入浅出 MySQL 内部架构:服务层、存储引擎与文件系统全覆盖
java·开发语言·数据库·学习·mysql·spring·微服务
南玖yy3 小时前
Linux 桌面市场份额突破 5%:开源生态的里程碑与未来启示
linux·运维·服务器·汇编·科技·开源·gradle
泰勒疯狂展开4 小时前
Linux研学-MySQL安装
linux·mysql·adb
霜绛4 小时前
机器学习笔记(三)——决策树、随机森林
人工智能·笔记·学习·决策树·随机森林·机器学习
站住前面的二哈5 小时前
Cartographer安装测试与模块开发(三)--Cartographer在Gazebo仿真环境下的建图以及建图与定位阶段问题(实车也可参考)
学习·ubuntu
Vesan,5 小时前
【Linux/Ubuntu】VIM指令大全
linux·ubuntu·vim
★YUI★6 小时前
学习游戏制作记录(克隆技能)7.25
学习·游戏·unity·c#
丨千纸鹤丨6 小时前
高可用集群Keepalived
linux·服务器·网络
屁股割了还要学6 小时前
【C语言进阶】柔性数组
c语言·开发语言·数据结构·c++·学习·算法·柔性数组
☞下凡☜7 小时前
C语言(20250722)
linux·c语言·开发语言