套接字(Socket)按照操作类型可以分为三类: 1.流式套接字(SOCK_STREAM):面向连接的Socket,只能收发 TCP 协议的数据; 2.数据报式套接字(SOCK_DGRAM):面向无连接的Socket,只能收发 UDP 协议的数据; 3.原始套接字(SOCK_RAW)可以用来自行组装数据包,可以接收本机网卡上所有的数据帧(数据包),直接操作系统网络核心(Network Core)。 Socket基本数据结构 1.套接字地址结构 IPV4 A.新式机构 <netinet/in.h> struct sockaddr_in { unsigned short sin_len; //IPv4地址长度 short int sin_family; //指代协议簇,在TCP套接字编程只能是AF_INET unsigned short sin_port; //存储端口号(使用网络字节顺序),数据类型是一个16为的无符号整形类型 struct in_addr sin_addr;//存储IP地址,IP地址是一个in_add结构体(结构在下面) unsigned char sin_zero[8]; //为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节 }; struct in_addr { unsigned long s_addr; //按照网络字节顺序存储IP地址 }; 大端模式和小端模式 1)小端就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 2)大端就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。 举一个例子,比如数字0x12 34 56 78在内存中的表示形式为: A. 大端模式: 低地址 -----------------> 高地址 0x12 | 0x34 | 0x56 | 0x78 B. 小端模式: 低地址 ------------------> 高地址 0x78 | 0x56 | 0x34 | 0x12 B.老式结构 struct sockaddr { unsigned short sa_family; //套接字的协议簇地址类型,TCP/IP协议对于IPv4地址类型为AF_INET char sa_data[14];//存储具体的协议地址 }; IPV6 A.新式结构 <netinet/in.h> struct sockaddr_in6 { unsigned short int sin6_len; //IPv6结构长度,是一个无符号的8为整数,表示128为IPv6地址长度 short int sin6_family; //地址类型AF_INET6 unsigned short int sin6_port; //存储端口号,按网络字节顺序 unsigned short int sin6_flowinfo; //低24位是流量标号,然后是4位的优先级标志,剩下四位保留 struct in6_addr sin6_addr; //IPv6地址,网络字节顺序 }; B.老式结构 struct in6_addr { unsigned long s6_addr; //128位的IPv6地址,网络字节顺序 }; 常用函数 1.socket函数 函数:int socket(int, int, int); 功能:创建一个套接字 解释:int socket(int af, int type, int protocol);
socket函数的family常值 socket函数的type常值 socket函数的protocol常值 socket函数中family和type参数的组合 2.bind函数 函数:int bind(int, const struct sockaddr *, socklen_t) 功能:将套接字绑定到指定端口和地址上 解释: int bind( int sockfd , const struct sockaddr * my_addr, socklen_t addrlen);
3.listen函数 函数:int listen(int, int) 功能:将套接字设置为监听模式,对于流式套接字,必须处入监听模式才能够接收客户端套接字的连接 解释:int listen(int sockfd, int backlog);
4.accept函数 函数:int accept(int, struct sockaddr * __restrict, socklen_t * __restrict) 功能:接受客户端的连接,在流式套接字中,只有在套接字处入监听状态,才能接受客户端的连接 解释:int accept(int sockfd, struct sockaddr *addr, int *addrlen);
5.close函数 函数:int close(int) 功能:关闭套接字 解释:int close(int sockfd); 6.connect函数 函数:int connect(int, const struct sockaddr *, socklen_t) 功能:发送一个连接请求 解释:int connect(int sockfd,const struct sockaddr * addr_server, int addrlen)
connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或出错时才返回,其中出错有如下几种情况: 1).若TCP客户没有收到SYN包的响应,则返回ETIMEDOUT错误。如调用该函数时,内核发送一个SYN,若无响应则等待6s后再发一个,若仍无响应,则等待24s再发一个,若总共等了75s后仍未收到响应消息则返回该错误(因内核而异)。 2).若响应时RST,表明该服务器主机在我们指定的端口上没有进程等待,客户收到RST包后马上返回ECONNREFUSED错误。 3).若客户发出的SYN在中间的路由器上引发了一个“destination unreachable”的ICMP错误,则按第一种情形继续发送SYN,若在规定的时间内没有收到回应,则将ICMP错误作为EHOSTUNREACH或ENETUNREACH错误返回。 7.recv函数 函数:ssize_t recv(int, void *, size_t, int) 功能:从流式套接字中接受数据,平时开发针对TCP套接字接收数据 解释:ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags)
成功时返回接收的字节数(收到EOF是返回0),失败是返回-1 8.send函数 函数:ssize_t send(int, const void *, size_t, int) 功能:在流式套接字中发送数据 解释:ssize_t send(int sockfd, const void *buff, size_t nbytes, int flags //表示函数的调用方式,一般填0,具体看下面表格 )
返回值:成功返回发送的字节数,错误返回-1 9.recvfrom函数 函数:ssize_t recvfrom(int, void *, size_t, int, struct sockaddr * __restrict, socklen_t * __restrict) 功能:用于接收一个数据包,并保存源地址 解释: ssize_t recvfrom(int sockfd, void * buff, size_t nbytes, int flags, struct sockaddr * __restrict from, socklen_t * __restrict fromLen)
返回值:如果正确接收返回接收到的字节数,失败返回-1. 10.sendto函数 函数:ssize_t sendto(int, const void *, size_t, int, const struct sockaddr *, socklen_t) 功能:向指定的目的地方发送数据 解释:ssize_t sendto(int sockfd, const void * buff, size_t nbytes, int flags, const struct sockaddr * to, socklen_t tolen)
成功则返回实际传送出去的字符数,失败返回-1,错误原因存于errno 中 辅助函数 1.htons() 函数 和 ntohs()函数 函数:u_short htons(u_short hostshort) 功能:将一个16位的无符号端整形数据由主机排列方式转换成网络排列方式,所谓的网络排列方式就是大端排列方式,MacOS是采用小端的存储方式存储数据 使用地方:在有关主机地址和端口号结构体中struct sockaddr_in里面,属性in_port_t sin_port表示端口号,因为端口号要用网络排列方式,使用该函数转换后赋值 函数: u_short ntohs(u_short netshort) 功能: 与htons()功能相反,将16位无符网络排列端口转换成主机排列方式,也就是将16位大端排列数字转换成小端排列方式 使用地方: 得到地址结构体struct sockaddr_in,将里面的in_port_t sin_port转换成我们平时看到的小端排列的端口号 2.htonl() 函数 和 ntohl()函数 函数:u_long htonl(u_long hostlong) 功能:将一个32位无符号整形由主机排列方式转换成网络排列方式,所谓的网络排列方式就是大端排列方式 使用地方:在有关主机地址和端口号结构体中struct sockaddr_in里面,结构体属性struct in_addr sin_addr中的in_addr_t s_addr属性表示IP地址信息,因为IP地址信息要用网络排列方式,使用该函数转换后赋值 函数:u_long ntohl(u_long netlong) 功能:与函数 htonl()功能相反,将网络排列的32位无符数据转换成主机排列,就是将32位大端排列数字转换成小段排列数据 使用地方:得到地址结构体struct sockaddr_in,将里面的in_addr_t s_addr转换成我们平时看到的小端排列32位IP地址 3.inet_addr 函数 函数:in_addr_t inet_addr(const char *) 功能:将存储IP地址的char字符串转换成网络排列方式的32位无符号整形,跟上面htonl()函数功能一样 使用地方:转换的结果可直接用来给地址信息结构体里面的IP地址赋值,因为转换出来的结果是网络排列的 4.inet_aton 函数 函数:int inet_aton(const char *, struct in_addr *); 功能:与函数inet_addr功能一样,将char字符串IP地址转换成网络排序的无符整形,传入struct in_addr结构体指针,直接赋给结构体 5.inet_pton 函数 函数:int inet_pton(int, const char *, void *); 功能:与辅助函数htonl()、inet_addr()、inet_aton()的功能一样,将char字符串IP地址转换成网络排序的无符整形,直接赋给struct in_addr结构体指针里面,不一样的是可以根据地址族的不同转换IPv6还是IPv4的地址 6.inet_ntoa 函数 函数:char *inet_ntoa(struct in_addr) 功能:正好与上面的函数inet_aton功能相反,需要传入一个关于地址信息的结构体,解析出来C字符串的IP地址 7.inet_ntop 函数 函数:const char *inet_ntop(int, const void *, char *, socklen_t); 功能:跟上面函数inet_ntoa()功能相似,于函数inet_pton()功能相反,不一样的是他可以传入地址族,传入AF_INET则解析出IPv4的地址,传入AF_INET6则解析 8.getpeername 函数 函数:int getpeername(int, struct sockaddr * __restrict, socklen_t * __restrict) 功能:获取socket套接字对方的地址信息,返回0时正常,否则错误 解释:int getpeername(int sockfd, struct sockaddr * peerAddr, socklen_t * addrLen)
8.getsockname 函数 函数:int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict) 功能:获取socket套接字的地址信息,返回0时正常,否则错误 解释:int getsockname(int sockfd, struct sockaddr * addr, socklen_t *addrLen)
|
|
来自: 西北望msm66g9f > 《培训》