我是靠谱客的博主 舒适香氛,最近开发中收集的这篇文章主要介绍linux tcp的结构体编程,Linux编程:TCP编程基础,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

参考书:《Linux网络编程(第2版)》,宋敬彬等编著。

1.TCP通信流程

30d3d916f57f7c0d4dda8aad3b7495e5.png

tcp连接过程

图片来源: https://blog.csdn.net/u012234115/article/details/54142273

2. 套接字基础知识

通用套接字数据结构

struct sockaddr{ //套接字地址结构

sa_family_t sa_family, //协议族,类型为usigned_short

char sa_data[14] //协议族数据

}

实际使用的套接字数据结构

struct sockaddr_in { //以太网套接字地址结构

u8 sin_len, //本结构体的长度

u8 sin_family, //协议族,通常与socket的domain相同

u16 sin_port, //16位的端口号,网络字节序

struct in_addr sin_addr, //IP地址,32位

char sin_zero[8] //未用

}

struct in_addr{ //IP地址结构

u32 s_addr //32位IP地址,网络字节序

}

sockaddr_in.sin_family一般取值AF_INET表示TCP/IP协议。

sockaddr与sockaddr_in的大小完全一致,因此通常使用sockaddr_in进行设置,然后强制转换为sockaddr。

3. 创建套接字函数 socket()

socke()函数建立一个套接字文件描述符,调用成功返回文件描述符,失败返回-1.

#include #include int socket(

int domain, //设置网络通信域,根据此参数选择协议族

int type, //设置套接字类型

int protocol //用于指定某个协议的特定类型

)

domain

名称

含义

名称

含义

PF_UNIX,PF_LOCAL

本地通信

PF_X25

ITU-T X.25/ISO-8208协议

PF_INET,AF_INET

IPv4 Internet协议

PF_AX25

amateur radio AX.25协议

PF_INET6

IPv6 Internet协议

PF_ATMPVC

原始ATM PVC访问

PF_IPX

IPX-Novell协议

PF_APPLETALK

appletalk

PF_NETLINK

内核用户界面设备

PF_PACKET

底层包访问

type

名称

含义

SOCK_STREAM

Tcp连接,支持带外数据传输

SOCK_DGRAM

支持udp连接

SOCK_SEQPACKET

序列化包

SOCK_RAW

Raw类型,提供原始网络协议访问

SOCK_RDM

提供可靠的数据报文,不过可能数据会有乱序

SOCK_PACKET

专用类型,不能在通用程序中使用

SOCK_STREAM的套接字表示双向的字节流,与管道类似,流式套接字在进行通信之前必须已经使用connect()建立连接。连接中可以使用read() 和write()进行数据传输。流式通信保证数据不会丢失或重复接受,当数据在一定时间内仍没有接受完毕,可认为这个连接已经死掉。

protocol

用于指定某个协议的特定类型,通常协议中只有一种类型,protocol取值为0.

errno

含义

EACCES

没有权限建立制定的domain的type的socket

EAFANOSUPPORT

不支持所给的地址类型

EINVAL

不支持此协议或者协议不可用

EMFILE

进程文件表溢出

ENFILE

已经达到系统允许打开的文件数量,打开文件过多

ENOBUFS/ENOMEM

内存不足。socket只有到资源足够或者有进程释放内存

EPROTONOSUPPORT

制定的协议type在domain中不存在

其他

4. 绑定地址端口 bind()

bind()函数将套接字和指定的端口进行绑定,如果使用connect()函数则没有绑定的必要。绑定成功返回0,失败返回-1.

#include #include int bind(

int sockfd, //文件描述符

const struct sockaddr *my_addr, //sockaddr结构体指针

socket_t addrlen //sockaddr结构体的长度

)

errno

含义

备注

EADDRINUSE

给定地址已用

EBADF

sockfd不合法

EINVAL

sockfd已经绑定到其他地址

ENOTSOCKET

sockfd不是socket描述符

EACCESS

地址被保护,用户权限不足

待补充

5. 监听本地端口 listen()

服务器顺序处理客户端连接,同一时间只能处理一个客户端连接。当多个客户端连接请求同时到来时,将不能处理的客户端连接请求放到等待队列中,队列长度由listen()定义。

listen()函数仅对SOCK_STREAM和SOCK_SEQPACKET的协议有效。

设置成功返回0,失败返回-1.

#include int listen(

int sockfd, //侦听的描述符

int backlog //队列最大长度

)

errno

含义

EADDRINUSE

另一个socket已经在同一端口侦听

EBADF

sockfd不合法

ENOTSOCK

sockfd不是socket的描述符

EOPNOTSUPP

socket不支持listen操作

6. 接收一个网络请求 accept()

当一个客户端的请求到达服务器时,会在队列中等待,直到服务器处理请求。

accept()函数执行成功,返回表示客户端连接的socket描述符,失败返回-1.

#include #include int accept(

int sockfd, //监听的文件描述符

struct sockaddr *addr, // 存储客户端信息的结构体

socket_len *addrlen //上结构体的长度

)

accept()函数调用成功后,会将客户端的信息存储在*addr指向的结构体中。

errno

含义

待补充

7. 连接目标服务器 connect()

客户端建立套接字之后,不需要进行绑定就可以使用connect()函数直接连接服务器。connect()成功返回0,失败返回-1.

#include #include int connect(

int sockfd, //需要与服务器连接的文件描述符

struct sockaddr *addr, //包含服务器信息的结构体

int addrlen // 上述结构体的长度

)

errno

含义

待补充

8. 写入函数 write() & send()

使用write()对套接字写入的方式与对普通文件的操作一样。

ssize_t write(

int fd, //文件描述符

const void *buf, //数据缓存区

size_t nbytes//写入字符的大小

);

返回值大于0:返回写入数据的大小,并不一定写入了指定的全部数据,所以一般放在while循环里。

返回值小于0:EINTR表示在写的时候出现了中断错误。EPIPE表示网络连接出现问题。

send()函数功能与write()类似,提供了第四个函数控制发送操作。

int send(

int sockfd,//文件描述符

void *buf,//数据缓存区

int len,//数据大小

int flags

);

flags值

含义

MSG_DONTROUTE

send函数使用的标志,表示目的主机在本地网络上,不需要查找表

MSG_OOB

可以接受和发送带外的数据

9. 读取函数 read() & recv()

read()从套接字中读取数据。

ssize_t read(

int fd,//文件描述符

void *buf,//数据缓存区

int length//要读的数据大小

);

返回值等于0:已经读到文件结尾。

返回值大于0:实际读的数据大小。

返回值小于0:与write相同。

recv()功能与read()类似,添加了第四个参数控制接受操作。

int recv(

int sockfd,//文件描述符

void *buf,//数据缓存区

int len,//数据大小

int flags

);

flags值

含义

MSG_OOB

可以接受和发送带外的数据

MSG_PEEK

recv使用的标志,只从缓冲区读取数据而清除其内容,下次读时仍然是一样的内容,一般用在多进程读写数据时

MSG_WAITALL

recv使用的标志,表示等到所有信息都到达时才返回。当1.读到指定数据大小,返回len2.读到文件结尾返回值小于等于len3.操作发生错误时返回-1

10. 关闭套接字 close() & shutdown()

关闭连接可以用close()实现,关闭之后就不再使用此描述符进行数据收发。

#include int close( int sockfd)

shutdown()函数可以使用更多方式关闭连接,调用成功返回0,失败返回-1。

#include int shutdown(

int sockfd, // 要关闭的描述符

int how //关闭方式

)

how

含义

SHUT_RD

0,切断读,不能通过此方式进行读操作

SHUT_WR

1,切断写,不能通过此方式进行写操作

SHUT_RDWR

2,切断读写,与close相同

最后

以上就是舒适香氛为你收集整理的linux tcp的结构体编程,Linux编程:TCP编程基础的全部内容,希望文章能够帮你解决linux tcp的结构体编程,Linux编程:TCP编程基础所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(41)

评论列表共有 0 条评论

立即
投稿
返回
顶部