socket编程基础
socket接口是一种特殊的I/O,也是一种文件描述符。
常见的socket类型:
SOCK_STREAM 流式scoket、提供可靠地面向连接的通信流;TCP,保证数据传输的正确性和顺序性
SOCK_DGRAM 数据报socket、无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠、无差错。UDP
原始socket 允许对底层协议如IP或ICMP进行直接访问。功能强大却不方便,常用于一些协议开发
地址结构相关处理
头文件
#include <netinet/in.h>
结构体定义
struct sockaddr
{
unsigned short sa_family;/* address族, AF_xxx */
charsa_data[14]; /* 14 bytes的协议地址 */
};
struct sockaddr_in{
short intsin_family; /* Internet地址族 */
unsigned shortint sin_port; /* 端口号 */
struct in_addrsin_addr; /* Internet地址 */
unsigned char sin_zero[8];/* 添0(和struct sockaddr一样大小)*/
};
这两个数据类型是等效的,可以相互转换,通常使用sockaddr_in更为方便
sa_family 可选常见值:
AF_INET:IPv4协议
AF_INET6:IPv6协议
AF_LOCAL:UNIX域协议
AF_LINK:链路地址协议
AF_KEY:秘钥socket
数据存储优先顺序
计算机数据存储有两种字节优先顺序:高位字节优先和低位字节优先,
Internet上数据以高位字节优先顺序。
所以在一些情况向需要对这两个字节存储优先顺序进行相互转化
头文件
#include <netinet/in.h>
函数原型
uint16_t htons(unit16_t host16bit);
uint32_t htonl(unit32_t host32bit);
uint16_t ntohs(unit16_t net16bit);
uint32_t ntohs(unit16_t net32bit);
n(network) h(host) s(short) l(long)
参数
host16bit:主机字节序的16bit数据
host32bit: 主机字节序的32bit数据
net16bit: 网络字节序的16bit数据
net32bit: 网络字节序的32bit数据
返回值
成功返回转化的字节序 失败返回-1
用户不需要清楚主机或者网络的数据存储优先顺序是否相等,直接调用就好,即使他们相等,那么该系统的这些函数会定义成空宏
地址格式转化
用户在表达地址时采用的是点分十进制(192.168.10.1),而在socket编程中所使用的是二进制值。所以需要转换。
IPv4里用到的函数有inet_aton inet_addr和inet_ntoa
我们使用inet_pton和inet_ntop 兼容IPv4和IPv6
inet_pton:将点分十进制地址映射为二进制地址
inet_ntop:将二进制地址映射为点分十进制地址
头文件
#include <arpa/inet.h>
函数原型
int inet_pton(int family,constchar*strptr,void*addrptr);
参数
family: AF_INET:IPv4协议 AF_INET6:IPv6协议
strptr: 要转换的值
addrptr: 转化后的地址
返回值
成功0失败-1
头文件
#include <arpa/inet.h>
函数原型
int inet_ntop(int family,void*addrptr, char*strptr,size_t len);
参数
family: AF_INET:IPv4协议 AF_INET6:IPv6协议
addrptr: 转化后的地址
strptr: 要转换的值
len :转化后的大小
返回值
成功0失败-1
socket函数
这个函数建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。如果函数调用成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1。
头文件
#include<sys/types.h>
#include<sys/socket.h>
函数原型
int socket(int domain, int type, int protocol);
参数
domain:AF_INET:IPv4协议、AF_INET6:IPv6协议、AF_LOCAL:UNIX域协议、AF_LINK:链路地址协议、AF_KEY:秘钥socket。
type:SOCK_STREAM 流式scoket SOCK_DGRAM数据报socket SOCK_RAW原始socket
protocol:0(原始套接字除外)
返回值
成功,会返回一个标识这个套接字的文件描述符,失败的时候返回-1。
bind函数
bind()函数将长度为addlen的struct sockadd类型的参数my_addr与sockfd绑定在一起,将sockfd绑定到某个端口上,如果使用connect()函数则没有绑定的必要。
头文件
#include<sys/types.h>
#include<sys/socket.h>
函数原型
int bind(int sockfd, const struct sockaddr *my_addr,socklen_t addrlen);
参数
第1个参数sockfd是用socket()函数创建的文件描述符。
第2个参数my_addr是指向一个结构为sockaddr参数的指针,sockaddr中包含了地址、端口和IP地址的信息。在进行地址绑定的时候,需要弦将地址结构中的IP地址、端口、类型等结构struct sockaddr中的域进行设置之后才能进行绑定,这样进行绑定后才能将套接字文件描述符与地址等接合在一起。
第3个参数addrlen是my_addr结构的长度,可以设置成sizeof(struct sockaddr)。使用sizeof(struct sockaddr)来设置套接字的类型和其对已ing的结构。
返回值
bind()函数的返回值为0时表示绑定成功,-1表示绑定失败
listen函数
listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int listen(int sockfd, int backlog);
参数
sockfd:被listen函数作用的套接字。服务器套接字文件描述符
backlog:请求队列中允许的最大请求数,大多数系统缺省值为20
返回值
成功0 失败-1
accpet函数
accept函数由TCP服务器调用,用于从已完成连接队列返回下一个已完成连接。如果已完成连接队列为空,那么进程被投入睡眠(假定套接字默为默认的阻塞方式)
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int accept(int sockfd, struct sockaddr *addr, socklen_t*addrlen);
参数
sockfd:socket函数返回的套接字描述符
addr和addrlen用来返回已连接的对端进程(客户端)的协议地址。如果我们对客户端的协议地址不感兴趣,可以把arrd和addrlen均置为空指针
返回值
成功0 失败-1
connect函数
connect函数通常用于客户端建立tcp连接。
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int connect (int sockfd,struct sockaddr * serv_addr,intaddrlen);
参数
sockfd:标识一个套接字。
serv_addr:套接字s想要连接的主机地址和端口号。
addrlen:name缓冲区的长度。
返回值
成功0 失败-1
sendto函数和recvfrom函数
sendto(),是把UDP数据报发给指定地址;recvfrom()是从指定地址接收UDP数据报。
头文件
#include <sys/types.h>
#include <sys/socket.h>
函数原型
int sendto (int s, const void *buf, int len, unsignedint flags, const struct sockaddr *to, int tolen);
int recvfrom(int s, void *buf, int len, unsigned intflags, struct sockaddr *from, int *fromlen);
参数
s: socket描述符。
buf: UDP数据报缓存地址。
len: UDP数据报长度。
flags: 该参数一般为0。
to: sendto()函数参数,struct sockaddr_in类型,指明UDP数据发往哪里报。
tolen: 对方地址长度,一般为:sizeof(struct sockaddr_in)。
fromlen:recvfrom()函数参数,struct sockaddr_in类型,指明从哪里接收UDP数据报。
返回值
对于sendto()函数,成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中。
对于recvfrom()函数,成功则返回接收到的字符数,失败则返回-1,错误原因存于errno中。
TCP读写可以用流read、write来实现,这里不再详谈。