专业的网站建设公哪家专业,网站开发 源代码,房地产最新消息新政策,温州合作网站文章目录 网络字节序socket编程socket 常见APIsockaddr结构 UDP编程创建socket绑定socketsendto发送数据recvform接收数据关闭socket TCP编程创建socket绑定socketlisten监听套接字accept服务端接收连接套接字connect客户端连接套接字send发送数据recv接收数据关闭socket 工具n… 文章目录 网络字节序socket编程socket 常见APIsockaddr结构 UDP编程创建socket绑定socketsendto发送数据recvform接收数据关闭socket TCP编程创建socket绑定socketlisten监听套接字accept服务端接收连接套接字connect客户端连接套接字send发送数据recv接收数据关闭socket 工具netstattelnet地址转换函数 socket编程注意细节代码案例 网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分网络数据流同样有大端小端之分。 TCP/IP协议规定网络数据流应采用大端字节序即低地址高字节。不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据。为使网络程序具有可移植性使同样的C代码在大端和小端计算机上编译后都能正常运行可以调用以下库函数做网络字节序和主机字节序的转换。 h表示hostn表示networkl表示32位长整数s表示16位短整数。 htonl表示将32位的长整数从主机字节序转换为网络字节序。 ntohl表示将32位的长整数从网络字节序转换为主机字节序。 socket编程
socket套接字通常指的是封装了ip和port的结构体其是网络编程中的一种通信机制支持TCP/IP的网络通信的基本操作单元简单的说就是通信的两方的一种约定用套接字中的相关函数来完成通信过程。 socket 常见API
// 创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)
int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);sockaddr结构 套接字分类
域间套接字 —— 本地通信原始套接字 —— 允许绕过传输层直接跟底层打交道主要用来写一些工具。网络套接字 —— 网络通信
理论上是三种应用场景对应的应该是三套接口但是Linux设计套接字的时候不想设计过多的接口所以Linux将所有的接口进行了统一只使用sockaddr结构体来描述这三种场景。 但是真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。 UDP编程
创建socket
#include sys/types.h
#include sys/socket.h
// 创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)
int socket(int domain, int type, int protocol);
//参数
domain:指定网络层的协议AF_INT: 使用ipv4版本的ip协议AF_INT6:使用ipv6版本的ip协议AF_UNIX:本地通信
type: 指定套接字的类型SOCK_DGRAM :使用UDP数据报套接字SOCK_STREAM:使用TCP字节流套接字
protocol指定使用的协议0使用套接字类型对应的默认协议绑定socket
int bind(int socket, const struct sockaddr* address,socklen_t address_len);*
//参数
sockfd socket函数返回的套接字描述符
addr 地址信息结构体成员struct sockaddr 是一个通用地址信息结构
address_len地址信息结构的长度sendto发送数据
ssize_t sendto(int sockfd, const void* buf, size_t len, int flags, const struct sockaddr* dest_addr, socklen_t addrlen);
//参数
sockfd 套接字描述符
buf 要发送的数据
len 发送数据的长度
flags 0-阻塞发送
dest_addr: 目标主机的地址信息结构体
addrlen 目标主机地址信息结构体的长度
//返回值
成功返回发送的字节数量,失败返回-1recvform接收数据
ssize_t recvfrom(int sockfd, void* buf, size_t len, int flags,struct sockaddr* src_addr, socklen_t* addrlen);
//参数
sockfd 套接字描述符
buf 将数据接收到buf当中
len buf的最大接收能力
flags 0-阻塞接收
src_addr 数据来源的主机地址信息结构体
addrlen 输入输出型参数
//返回值
成功则返回实际接收到的字符数失败返回-1错误原因会存于errno中关闭socket
close(int sockfd);
//sockfd 套接字描述符TCP编程
创建socket
#include sys/types.h
#include sys/socket.h
// 创建 socket 文件描述符 (TCP/UDP, 客户端 服务器)
int socket(int domain, int type, int protocol);
//参数
domain:指定网络层的协议AF_INT: 使用ipv4版本的ip协议AF_INT6:使用ipv6版本的ip协议AF_UNIX:本地通信
type: 指定套接字的类型SOCK_DGRAM :使用UDP数据报套接字SOCK_STREAM:使用TCP字节流套接字
protocol指定使用的协议0使用套接字类型对应的默认协议
//返回值
socket()打开一个网络通讯端口,如果成功的话,就像open()一样返回一个文件描述符程序可以像读写文件一样用read/write在网络上收发数据;调用出错则返回-1绑定socket
int bind(int socket, const struct sockaddr* address,socklen_t address_len);*
//参数
sockfd socket函数返回的套接字描述符
addr 地址信息结构体成员struct sockaddr 是一个通用地址信息结构
address_len地址信息结构的长度listen监听套接字
//listen()声明sockfd处于监听状态
int listen(int sockfd, int backlog);
//参数
sockfd 套接字描述符
backlog已完成连接队列的大小
//返回值成功0失败-1当客户端和服务端进行三次握手的时候会存在两种状态连接还未建立和连接已建立此时操作系统内核中就会存在两个队列未完成连接队列和已完成连接队列。当完成三次握手后会由未完成连接队列放到已完成连接队列而backlog就是已完成连接队列的大小backlog影响了服务端并发接收连接的能力。
accept服务端接收连接套接字
//从已经完成连接队列中获取已经完成三次握手的连接没有连接时调用accept会阻塞等待。
int accept(int sockfd, struct sockaddr* addr, socklen_t * addrlen);
//参数
sockfd套接字描述符(listen_sockfd)
addr输出型参数保存客户端地址信息结构(客户端IP客户端的端口)
addrlen输入输出参数传入缓冲区的大小传出客户端地址信息结构的长度
//返回值成功返回新连接的套接字描述符失败返回-1三次握手的时候是对listen_sockfd进行操作当调用accept()会在Tcp服务端内部创建一个新的套接字new_sockfd三次握手之后的数据收发都是多new_sockfd进行操作。 connect客户端连接套接字
//客户端需要调用connect()连接服务器
int connect(int sockfd, const struct sockaddr * addr,socklen_t addrlen);
//参数
sockfd套接字描述符(listen_sockfd)
addr服务端地址信息结构(服务端IP服务端的端口)
addrlen服务端地址信息结构的长度
//返回值成功返回0小于0连接失败send发送数据
ssize_t send(int sockfd, const void * buf, size_t len, int flags);//参数
sockfd套接字描述符(new_sockfd)
buf待要发送的数据
len发送数据的长度
flags0阻塞发送MSG_OOB发送带外数据在紧急情况下所产生的数据会越过前面进行排队的数据优先进行发送。//返回值大于0返回发送的字节数量-1发送失败recv接收数据
ssize_t recv(int sockfd, void * buf, size_t len, int flags);//参数
sockfd套接字描述符(new_sockfd)
buf将接收的数据放到buf
lenbuf的最大接收能力
flags0阻塞发送如果客户端没有发送数据调用recv会阻塞//返回值大于0正常接收了多少字节数据等于0对端将连接关闭了小于0接受失败关闭socket
close(int sockfd);
//sockfd 套接字描述符工具
netstat
netstat -anp | grep [端口号]查看端口的使用情况
telnet
进入cmd使用telnet模仿TCP三次握手建立连接在cmd窗口输入 “tenlet 公网IP 端口号” 即可模拟测试 地址转换函数
sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP 地址但是我们通常用点分十进制的字符串表示IP 地址,以下函数可以在字符串表示 和in_addr表示之间转换
字符串转in_addr的函数: in_addr转字符串的函数: inet_ntoa函数把这个返回结果放到了静态存储区这个时候不需要我们手动进行释放。
socket编程注意细节
客户端没有必要调用bind()固定一个端口号否则如果在同一台机器上启动多个客户端就会出现端口号被占用导致不能正确建立连接。服务器也不是必须调用bind()但如果服务器不调用bind(), 内核会自动给服务器分配监听端口, 每次启动服务器时端口号都不一样客户端要连接服务器就会遇到麻烦。多进程的客户端代码和单进程是一样的父进程负责accept子进程负责数据的接收和发送若子进程一直不退出则父进程一直在等待永远无法接收新连接可以使用自定义信号处理方式将SIGCHLD信号重新定义当子进程退出发出SIGCHLD信号时父进程则对子进程的资源进行回收。建立好了tcp连接之后我们就可以把得到的fd当作文件描述符来使用也可以使用read和 write函数进行读写。 代码案例
UDP案例
UDP · 程序员Jared/Linux - 码云 - 开源中国 (gitee.com)
TCP案例
TCP · 程序员Jared/Linux - 码云 - 开源中国 (gitee.com)