Linux Socket编程-基础知识点

套接字(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);

  • af:表示一个地址家族,IPv4连接时填AF_INET,IPv6连接时对应AF_INET6

  • type:表示套接字类型,如果是SOCK_STREAM表示创建面向连接的流式套接字;如果是SOCK_DGRAM表示面向无连接的数据包套接字;为SOCK_RAW表示创建原始套接字

  • protocol:表示套接口所用的协议,如果用户不指定,可以设置为0

  • 返回值:int类型的一个指向传输提供者的句柄(套接字)

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);

  • sockfd:表示套接字标识

  • my_addr:是一个指向struct sockaddr结构体类型的指针,一般绑定 IPv4地址传入struct sockaddr_in指针,IPv6地址传入struct sockaddr_in6指针(PS:这里我也不是很清楚,sockaddr_in结构体里面有地址族,改变地址族为IPv6的不知道行不行,下面的演示和注释以前面的struct sockaddr_in结构体为主),都包含地址和端口号信息,强转成需要的类型

  • addrlen:确定my_addr缓冲区的长度,就是前面结构体的大小

  • 返回值:如果函数执行成功,则返回值为0,失败则为-1

3.listen函数


函数:int listen(int, int)


功能:将套接字设置为监听模式,对于流式套接字,必须处入监听模式才能够接收客户端套接字的连接


解释:int listen(int sockfd, int backlog);

  • sockfd:表示套接字标识

  • backlog:表示等待连接的最大队列长度。例如:如果backlog被设置为2,此时有3个客户端同时发出连接请求,那么前两个客户端会放置在等待连接队列中,第三个客户端会得到错误信息。

  • 返回值:成功则返回0,失败则返回-1

4.accept函数


函数:int accept(int, struct sockaddr * __restrict, socklen_t * __restrict)


功能:接受客户端的连接,在流式套接字中,只有在套接字处入监听状态,才能接受客户端的连接


解释:int accept(int sockfd, struct sockaddr *addr, int *addrlen);

  • sockfd:表示套接字标识

  • addr:是一个sockaddr_in结构体指针,接收连接端地址信息

  • addrlen:前面sockaddr_in结构体地址长度指针,用来接收连接端地址信息结构体长度

  • 返回值:一个新的套接字,它对应于已经接受的客户端连接,对于该客户端的所有后续操作,都应使用这个新的套接字

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)

  • sockfd:表示一个正准备连接的套接字。客户端连接套接字int socket_client

  • addr_server:存储套接字要连接主机的地址信息结构体指针

  • addrlen:前面结构体的也就是addr_server结构体缓冲区的长度

  • 返回值:成功则返回0,失败则返回-1

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)

  • sockfd表示流式套接字

  • buff用来存放recv函数接收到的数据的缓冲区

  • nbytes缓冲区的长度

  • flags 表示函数的调用方式,一般填0

成功时返回接收的字节数(收到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,具体看下面表格

)

  • sockfd表示流式套接字

  • buff存放要发送数据的缓冲区

  • 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)

  • sockfd表示准备接收的套接字

  • buff指向缓冲区的指针,用来接收数据

  • nbytes表示缓冲区的长度

  • flags表示调用方式,一般填0

  • __restrict from是一个指向地址结构体的指针,用来接收发送数据方的地址信息

  • __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)

  • sockfd表示准备发送数据的套接字

  • buff指向缓冲区的指针,该缓冲区包含将要发送的数据

  • nbytes缓冲区数据长度

  • flags表示调用方式,一般填0

  • to指向目标套接字地址的结构体指针

  • 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)

  • sockfd:表示套接字

  • peerAddr:接收地址信息结构体,传入结构体指针外面申明里面赋值,获取到的是连接对象的地址信息

  • addrLen:地址信息结构体的长度指针

  • 返回值:返回0时可以通过地址信息指针取里面的信息,<0时错误

8.getsockname 函数


函数:int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict)
功能:获取socket套接字的地址信息,返回0时正常,否则错误


解释:int getsockname(int sockfd, struct sockaddr * addr, socklen_t *addrLen)

  • sockfd:表示套接字

  • addr:接收地址信息结构体,传入结构体指针外面申明里面赋值,获取到的是sockfd的地址信息

  • addrLen:地址信息结构体的长度指针

  • 返回值:返回0时可以通过地址信息指针取里面的信息,<0时错误

(0)

相关推荐