Linux—socket网络编程基本函数(二)

        开头:进程间通信有消息传递机制(管道,FIFO,消息队列),同步机制(互斥量,条件变量,互斥锁,信号量),共享内存机制。socket也是用来进程间通信的,只不过是网络进程间的通信。下面就linux socket一些函数及编程小结。

1.       Socket:

(1)     Socket地址结构:大多数socket函数需要一个指向socket地址结构的指针作为实参。每个协议族都定义了自身的socket地址结构,这些结构的名字都以sockaddr_开始。

IPV4 socket地址结构通常称为“Internet socket address structure”,且命名为sockaddr_in。包含在头文件<netinet/in.h>

struct sockaddr_in

{

short int sa_family;//地址族

unsigned short int sin_port;//端口号

struct in_addr sin_addr;//ip地址

unsignd char sin_zero[8];

};


(2)    socket地址结构中的三个成员:
sin_family:
sin_addr
sin_port
in_addr_t数据类型必须是一个unsigned int型(至少32bits),in_port_t必须是一个unsigned int型(至少16位),sa_family_t可以是任何unsigned int型。


(3)       IPV4地址和TCP或者UDP端口号总是以网络字节序存储。
(4)    主机字节序:大端序(高字节在起始地址)和小端序。
说明,将一个地址绑定到socket时,先将主机字节序转换成网络字节序。

(5)常见的socket类型:有流式socket(SOCK_STREAM),提供可好的面向连接的通信,使用TCP协议,保证了数据的正确性和可靠性。

数据报socket(SOCK_DGEAM),定义了无连接的服务,数据通过相互独立的报文进行传输,使用UDP协议,无序且不可靠。

原始socket,原始套接字允许对底层的协议进行访问,主要用于一些协议的开发。


2.       字节序函数:


internet协议使用big-endian字节序。通过使用下面4个函数进行字节序转变:
#include <netinet/in.h>
Unit16_t htons(unit16_t host16bitvalue);
Unit32_t htonl(unit32_t host32bitvalue);

上面返回返回值是以网络字节序
Unit16_t ntohs(unit16_t net16bitvalue)

Unit32_t ntohl(unit32_t net32bitvalue);

上面返回值是以主机字节序

3.       地址转换函数:


地址转换函数用于进行internet地址和ACSII字符串和网络字节序的二进制值之间的转换。


Inet_aton         inet_ntoa        inet_addr用于转换IPV4地址


Inet_pton         inet_btop                   即可以处理IPV4也可以处理IPV6地址。


包含在头文件<arpa/inet.h>中


Int inet_aton(const char *strptr,struct in_addr *addrptr);


转换网络主机地址strptr从addrptr指向的结构体。返回值为1成功,0为错误,并设置errno。


Strptr指向的地址可以支持以下几种类型:


(1)       A.b.c.d:每个数字部分代表地址的一个字节,这些地址按从左至右的顺序建立二进制的地址。


(2)       A.b.c:其中a和b代表二进制地址的前2个字节,而c是一个16位的值决定了这个二进制地址的最右边两位。这种标准适合于已经过时的B类网络地址。


(3)       A.b:a是这个二进制地址的首个字节,而b是一个24位的值决定了最右边的3个字节。这个标准适合于已经过时的C类网络地址。


(4)       A:是一个32位的值直接存储了二进制的网络地址而不需要任何二进制字节的重新排序。


全部转换为10进制,然后存储在addrptr指向的结构体数据成员中。


In_addr_t inet_addr(const char *ptrstr);


返回的32位二进制网络字节序IPV4地址


Char *inet ntoa(struct in_addr inaddr);


返回指向点分十进制的字符串的指针。把网络主机地址以给定的网络字节序,转换成一个IPV4的点分十进制的标号。返回的是一个静态分配的缓冲区,用来被后来的调用进行改写。


4.       基本的TCP socket:


整体的框图如下:






5.       Socket函数:


#include <sys/socket.h>

Int socket(int family,int type,int protocol);

成功,返回非负的描述符,这个标示符能够标识一个socket,错误返回-1

具体的参数说明: 


(1)Family指定协议族,常用的取值有:在头文件中定义


AF_INET:IPV4协议


AF_INET6:IPV6协议


AF_LOCAL,AF_UNIX:unix domain协议


        (2)Type指定socket类型。常见的socket类型有:


                   SOCK_STREAM:提供有序的,可靠的,双向的,基于字节流的连接。


                   SOCK_DGRAM:datagram socket,支持无连接的,不可靠的固定最大值长度的信息


                   SOCK_SEQPACKET:sequenced packet socket,提供了一个有序的,可靠的,双向基于为固定最大值长度的数据传输路径的连接;消费者需要读取一个完整的包在每个输入系统调用时。


                   SOCK_RAW:raw rocket提供了raw rocket网络的访问权限


(3)Protocol指定了协议的类型:常用的有IPPROTO_TCP和IPPROTO_UDP,protocol用来指定所使用的传输协议号,通常此参考不用管它,设置为0,表示自动选择type类型对应的默认协议。






说明,当使用socket函数创建socket后,返回的socket描述符存于协议族空间中,没有一个具体的地址,需要调用Bind函数。


6.  Bind函数:(对socket进行定位)


Bind函数给一个socket分配一个本地协议地址(local protocol address)。使用internet协议时,协议地址是32位的IPV4地址或者128位的IPV6地址以及16位的TCP或UDP端口号。


#include <sys/socket.h>


Int bind(int sockfd,const struct sockaddr *myaddr,socklen_t addrlen);


参数说明:


(1)sockfd:由socket函数创建的描述符,标识一个唯一的对应的socket端口。


(2) myaddr:const struct sockaddr*指针,指向要绑定的sockfd的协议地址,这个地址结构根据创建socket时设定的地址协议族不同而不同。


(3)对应的地址的长度


使用IPV4,当指定地址为常量INADDR_ANY时,表明由内核来选择IP地址。


 
7.       Listen函数:


Listen函数只能由TCP服务器调用,监听这个socket,主要执行两个动作:


(1)       转换一个未连接的socket(默认是主动类型的)为一个被动(passive socket),表明内核将接受即将到来的连接请求。


(2)       函数第2个参数指定了内核为这个socket排队的最大连接数。


#include <sys/socket.h>


Int listen(int sockfd,int backlog);


成功返回0,错误返回-1


 


对于一个listening socket,内核维持两个队列:


(1)       未完成的(incomplete)连接队列。该队列为每个SYN包含一个条目(entry),等待TCP三次握手的完成。


(2)       完成的连接队列(completed)。该队列为每个已经完成三次握手的客户端包含一个条目(entry)。


对Listening socket的两个队列说明:


当有客户端的SYN段到来时,TCP首先在incomplete队列中创建一个条目,然后发送三次握手的第2个段。这个条目将在incomplete队列上直到TCP收到第三个段到达。如果三次握手正常完成。这个条目将会转移到complete队列的尾端。当进程调用accept函数,complete队列的第一个条目就会被传送给进程使用。


 


8.   Connect函数:由TCP的客户端来建立一个与TCP服务器的连接(客户端调用)
 
#include <sys/socket.h>
 
Int connect(int sockfd,const struct sockaddr *servaddr,socklen_t addrlen);
 
成功返回0,出错返回-1
 
 参数说明:
Sockfd是socket函数返回的socket描述符。第2和3个参数是指向一个socket地址结构的指针和它的大小。Socket地址结构必须包含服务器的IP地址和端口号。
 
Connect函数初始化TCP的三次握手,只有在连接建立或者发生错误时才会返回。






9.       Accept函数:


Accept函数由TCP服务器调用,用来从completed队列的前端返回下一个已经完成的连接.


如果complete队列为空,进程将进入睡眠。


#include <sys/socket.h>


Int accept(int sockfd,struct sockaddr *cliaddr,socken_t *addrlen);


成功返回非负描述符,失败返回-1


参数说明:cliaddr和addrlen参数用来获得已经连接的客户端的协议地址。


如果accept函数成功,将返回一个由内核创建的新的描述符。这个新的描述符代表与客户端的TCP连接。Accept函数的第一个参数是listening socket,accept函数的返回值称为connected socket。服务器通常只创建一个listening socket。内核为每个已经接受的客户端创建一个connectedsocket。当服务器完成对客户端的服务时,就会关闭connected socket。



至此服务器就与客户端完成了连接,可以调用读写操作了。
发布了61 篇原创文章 · 获赞 6 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/shayueqing/article/details/12953931