socket网络编程
1、什么是套接字socket
套接字(socket) 是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单
机上进行,也可以跨网络进行。Linux所提供的功能( 如打印服务、连接数据库和提供Web页面)和网
络工具(如用于远程登录的rlogin和用于文件传输的ftp)通常都是通过套接字来进行通信的。套接字的创建和使用与管道是有区别的,因为套接字明确地将客户和服务器区分开来。套接字机制可以实现将多个客户连接到一个服务器。
2、主机字节序列和网络字节序列
(1)当在基于Intel处理器的Linux机器上运行新版本的服务器和客户程序时,我们可以用netstat命令来查看网络连接状况。这个命令在大多数配置了网络功能的UNIX系统上都能找到。它显示了客户/服
务器连接正在等待关闭。连接将在一小段超时时间之后关闭(具体的输出内容将随Linux版本的不同
而不同)。
(2)主机字节序列分为大端字节序和小端字节序,不同的主机采用的字节序列可能不同。大端字节序是指一个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。小端字节序则是指整数的高位字节存储在内存的高地址处,而低位字节则存储在内存的低地址处。在两台使用不同字节序的主机之间传递数据时,可能会出现冲突。所以,在将数据发送到网络时规定整形数据使用大端字节序,所以也把大端字节序成为网络字节序列。对方接收到数据后,可以根据自己的字节序进行转换。
Linux 系统提供如下 4 个函数来完成主机字节序和网络字节序之间的转换:
include <netinet/in.h>
uint32_t htonl(uint32_t hostlong); // 长整型的主机字节序转网络字节序
uint32_t ntohl(uint32_t netlong); // 长整型的网络字节序转主机字节序
uint16_t htons(uint16_t hostshort); // 短整形的主机字节序转网络字节序
uint16_t ntohs(uint16_t netshort); // 短整型的网络字节序转主机字节序
2、套接字地址结构
2.1 通用 socket 地址结构
socket 网络编程接口中表示 socket 地址的是结构体 sockaddr,其定义如下:
#include <bits/socket.h>
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
};
sa_family 成员是地址族类型(sa_family_t)的变量。地址族类型通常与协议族类型对应。常见的协议族和对应的地址族如下图所示:
2.2 专用 socket 地址结构
TCP/IP 协议族有 sockaddr_in 和 sockaddr_in6 两个专用 socket 地址结构体,它们分别用于 IPV4 和 IPV6:
struct in_addr
{
u_int32_t s_addr;
};
struct sockaddr_in
{
sa_family_t sin_family;
u_int16_t sin_port;
struct in_addr sin_addr;
};
struct in6_addr
{
unsigned char sa_addr[16]; // IPV6 地址,要用网络字节序表示
};
struct sockaddr_in6
{
sa_family_t sin6_family; // 地址族:AF_INET6
u_inet16_t sin6_port; // 端口号:用网络字节序表示
u_int32_t sin6_flowinfo; // 流信息,应设置为 0
struct in6_addr sin6_addr; // IPV6 地址结构体
u_int32_t sin6_scope_id; // scope ID,尚处于试验阶段
};
- sin_family: 地址族 AF_INET
- sin_port: 端口号,需要用网络字节序表示
- sin_addr: IPV4 地址结构:s_addr 以网络字节序表示 IPV4 地址
2.3 IP 地址转换函数
通常,人们习惯用点分十进制字符串表示 IPV4 地址,但编程中我们需要先把它们转化为整数方能使用,下面函数可用于点分十进制字符串表示的 IPV4 地址和网络字节序整数表示的 IPV4 地址之间的转换:
#include <arpa/inet.h>
in_addr_t inet_addr( const char *cp); //字符串表示的 IPV4 地址转化为网络字节序
char* inet_ntoa( struct in_addr in); // IPV4 地址的网络字节序转化为字符串表示
3、网络编程接口
头文件
#include <sys/types.h>
#include <sys/socket.h>
- int socket( int domain, int type, int protocol);
socket()创建套接字,成功返回套接字的文件描述符,失败返回-1 domain: 设置套接字的协议簇, AF_UNIX AF_INET AF_INET6
type: 设置套接字的服务类型 SOCK_STREAM SOCK_DGRAM
protocol: 一般设置为 0,表示使用默认协议
- int bind( int sockfd, const struct sockaddr *addr, socklen_t
addrlen);
bind()将 sockfd 与一个 socket 地址绑定,成功返回 0,失败返回-1
sockfd 是网络套接字描述符
addr 是地址结构
addrlen 是 socket 地址的长度
- int listen( int sockfd, int backlog);
listen()创建一个监听队列以存储待处理的客户连接,成功返回 0,失败返回-1
sockfd 是被监听的 socket 套接字
backlog 表示处于完全连接状态的 socket 的上限
- int accept( int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept()从 listen 监听队列中接收一个连接,成功返回一个新的连接 socket,该 socket 唯一地标识了被接收的这个连接,失败返回-1
sockfd 是执行过 listen 系统调用的监听 socket
addr 参数用来获取被接受连接的远端 socket 地址
addrlen 指定该 socket 地址的长度
- int connect( int sockfd, const struct sockaddr *serv_addr, socklen_t
addrlen);
connect()客户端需要通过此系统调用来主动与服务器建立连接,成功返回 0,失败返回-1
sockfd 参数是由 socket()返回的一个 socket。
serv_addr 是服务器监听的 socket 地址
addrlen 则指定这个地址的长度
- int close( int sockfd);
close()关闭一个连接,实际上就是关闭该连接对应的 socket
- ssize_t recv( int sockfd, void *buff, size_t len, int flags);
- ssize_t send( int sockfd, const void *buff, size_t len, int flags);
TCP 数据读写:
recv()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小
send()往 socket 上写入数据,buff 和 len 参数分别指定写缓冲区的位置和数据长度
flags 参数为数据收发提供了额外的控制
- ssize_t recvfrom( int sockfd, void buff, size_t len, int
flags,struct sockaddr src_addr, socklen_t*addrlen); - ssize_t sendto( int sockfd, void buff, size_t len, int flags,struct
sockaddr dest_addr, socklen_t addrlen);
UDP 数据读写:
recvfrom()读取 sockfd 上的数据,buff 和 len 参数分别指定读缓冲区的位置和大小
src_addr 记录发送端的 socket 地址
addrlen 指定该地址的长度
sendto()往 socket 上写入数据,buff 和 len 参数分别指定写缓冲区的位置和数据长度
dest_addr 指定接收数据端的 socket 地址
addrlen 指定该地址的长度
今天的文章Linux之socket网络编程(全)分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:http://bianchenghao.cn/28569.html