socket();创建一个套接字
当前正在学习的网络编程是基于linux系统的C++网络编程,上面是在linux下的socket定义
输入:
domain:翻译为域,这里就是制定为套接字选择的地址协议,常见的有IPV4、IPV6等
AF_INET IPv4 Internet protocols
AF_INET6 IPv6 Internet protocols
AF_UNIX Local communication
(linux翻译)domain参数指定通信域;这将选择用于通信的协议族。
type:创建套接字选择的数据传输协议,常见的有SOCK_STREAM数据流协议、SOCK_DGRAM数据报协议,一种是基于TCP协议,一种基于UDP协议
(linux)套接字具有指定的类型,该类型指定通信语义。当前定义的类型有:
SOCK_STREAM提供有序的、可靠的、双向的、基于连接的字节流。带外数据传输机制可以被支持。
SOCK_DGRAM支持数据报(无连接,固定最大长度的不可靠消息)。
protocol:协议类型,这个我也说不太清楚,一般默认为0即可
(linux)协议指定套接字要使用的特定协议。通常只存在一个单独的协议来支持一个部分
指定协议族中的Ular套接字类型,在这种情况下,protocol可以指定为0。然而,有可能很多
协议可能存在,在这种情况下,必须以这种方式指定特定的协议。使用的协议号是特定的
“交流领域”,交流将在其中发生;看到协议(5)。如何映射协议名请参见getprotoent(3)
协议号的字符串。
返回值:等下来补充
示例:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
socket(AF_INET,SOCK_STREAM,0);
bind();给套接字绑定一个名称,根据里面要传递的参数,其实就是给套接字绑定一个地址,这里后面等下会具体来说
struct sockaddr{
sa_family_t sa_family;
char sa_data[14];
};
sockfd:socket函数的返回值
const struct sockaddr *addr:要说起这个函数,可能需要提到一个概念性的问题。
上面是sockaddr的结构,因此为了传入有效的参数,我们需要去给参数进行赋值。
struce sockaddr_in addr;//初始化sockaddr,其实就是将sockaddr_in的结构用于sockaddr,具体原因我后面也会补充
addr.sin_family=AF_INET;
addr.sin_port=htons(8888);
addr.sin_addr.s_addr=htonl(INADDR_ANY);//默认写法
addr:&addr
addrlen:地址结构的大小,sizeof(addr)
这里时间不是很够,后面我会根据我的理解给出上面一些参数的原因,总的来说,参数的选择是跟套接字创建的时候的参数某种程度上面保持了一致性。
Linux:
下面是linux系统中,在创建套接字的过程中,使用了AF_UNIX,所以my_addr.sun_family = AF_UNIX;我的理解是这些部分是有一些联系的,而且在使用AF_UNIX之后,并不需要使用sockaddr_in
暂时说说我的理解(还没有去证实)sockaddr_in,用于IPV4通信
sockaddr_in6很显然,用于IPV6的通信
(一些其他的观点等待去验证)
sfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un my_addr, peer_addr;
my_addr.sun_family = AF_UNIX;
if (bind(sfd, (struct sockaddr *) &my_addr,
sizeof(my_addr)) == -1)
handle_error("bind");
返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
成功返回0,不成功返回-1,如果有错误就返回错误
示例:
struct sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_port=htonl(8888)
addr.sin_addr.s_addr=htonl(INADDR_ANY)
int sfd;
sfd=socket(.......);
bind(sfd,(struct sockaddr*)&addr,sizeof(addr);
listen();listen - listen for connections on a socket,设置与套接字连接的服务器的上限数值(同时与服务器进行3次握手的客户端数量)
sockfd:sockfd参数是一个文件描述符,引用SOCK_STREAM或SOCK_SEQPACKET类型的套接字。
这里的sockfd与bind()函数中的sockfd相同,都是socket();函数的返回值
backlog:backlog参数定义了sockfd的挂起连接队列可以增长到的最大长度。上限数值,最大128
返回值:On success, zero is returned. On error, -1 is returned, and errno is set appropriately.
成功返回0
示例:
int cfd;
struct sockaddr_in addr;
addr.sin_famliy=AF_INET;
addr.sin_port=htonl(8888);
addr.sin_addr.s_addr=htonl(INADDR_ANY);
cdf=socket(AF_INET,SOCK_STREAM,0);
accept(); accept a connection on a socket 阻塞客户端建立连接,成功的话,返回一个与客户端成功建立连接的套接字
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
accept()系统调用用于基于连接的套接字类型(SOCK_STREAM, SOCK_SEQPACKET)。它提取挂起连接队列上的第一个连接请求。监听套接字sockfd创建一个新的已连接套接字,并返回一个引用该套接字的新文件描述符。创建的套接字不在监听状态。原始套接字sockfd不受此调用的影响。参数sockfd是一个用socket(2)创建的套接字,用bind(2)绑定到本地地址,在listen(2)之后监听连接。
sockfd:套接字的返回值,准确的来说是服务器端通过调用正确调用socket -> bind -> listen 函数之后的用于指向存放多个客户端缓冲队列缓冲区的套接字描述符
*addr:是用来保存客户端套接字对应的内存空间变量(包括客户端IP和端口信息等)
*addrlen:第二个参数的大小
addr是一个传出参数,
示例:
connect();在一个套接字上面创建连接
connect()系统调用将文件描述符sockfd引用的套接字连接到由addr指定的地址。参数addrlen指定了addr的大小。addr中的地址格式由套接字sockfd的地址空间决定;详见socket(2)。如果套接字sockfd类型为SOCK_DGRAM,则addr是缺省情况下发送数据报的地址,也是接收数据报的唯一地址。如果socket类型为SOCK_STREAM或SOCK_SEQPACKET,则该调用尝试建立到绑定到addr指定地址的套接字的连接。一些协议套接字(例如UNIX域流套接字)可能只能成功地连接()一次。一些协议套接字(例如UNIX和Internet域中的数据报套接字)可能多次使用connect()来更改它们的关联。一些协议套接字(例如,TCP套接字以及UNIX和Internet域中的数据报套接字)可以通过连接到带有的地址来解除关联sockaddr的sa_family成员设置为AF_UNSPEC;此后,套接字可以连接到另一个地址。(AF_UNSPEC自内核2.2起在Linux上得到支持。)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
sockfd:产生的套接字参数
*addr:传入参数,指定服务器端地址信息,含IP地址和端口号
addrlen:第二个参数的长度
到这里,基本的通信所用到的函数就介绍完毕了,这两天也找了很多资料,但是始终很难有一个茅塞顿开的醒悟,所以就先暂时到这吧,后面继续学习,有了感悟,我会再后面重新再写一遍函数的介绍,总的来说,对于accept、socket等函数印象很深刻,但是对于connect以及bind还是有点模糊的概念,因为我确实也没搞定,某些参数的由来,虽然linux系统下面提供了源码,我也看了一些,但是确实还是很难理解,但是我记得这里是一个疑点,往后面学习,我还会回来的!
上次少更新的两个函数,在后面学习的过程中我才发现,现在先来简单说一下啦
inet_pton();
说到最后这两个函数,就要提到一些概念性的定义,例如我们常见的IP:192.168.8.88,这是一个十进制的网络字节序,但是在我们计算机中的网络字节序,可不是这种,而是一种二进制的网络字节序。
网络字节序:
类型:大端字节序、小端字节序
大端:最高有效位存于最低内存地址处,最低有效位存于最高内存处;(低到高)
小端:最高有效位存于最高内存地址,最低有效位存于最低内存处。(高到低)
这里由于一些原因,导致我们电脑本机使用的是小端字节序,而在网络中的数据传输使用的是大端字节序,因此在对数据进行传世时,需要进行转化。而现在也有着一些很合适的转化函数
1.htons、htonl,解释为Host to Network,从主机转换到网路,也就是表明,讲字节序由小端转化为大端,两个函数的区别主要是返回值的长短不同,s表示返回unsigned short int,l表示返回unsigned int
2、ntohs、ntohl,听懂了上面的解释,这两个函数的意思就显而易见了。Netword to Host,网络中的大端字节序转化为Host中的小端字节序。
后面的s、l是同一个意思,只是返回的值部同
明白了网络字节序,就明白了数据在网络中的传输基本都是二进制形式的,但是我们还是会经常看到ip 192.128.66.255 193.253.255.21等等这些ip,但是这些ip有一个共同的特点,就是这些ip都使用了十进制来表示,但是在机器语言中,传递的数据可能是这样0000. 0125.2352.1563
所以这里牵扯到如何讲ip转化为网络字节序的,这个地方就是我们今天要说的函数,inet_pton,inet_ntop,
两个函数就是将网络字节序和正常人类能看懂的进行一个转换,
1100.1200.1300.1400
所以在某些函数里面是需要使用十进制二维码,当然也可以手动转换
为此,这两个函数起到十进制和网络字节序之间的转换。