网络进程间通信:socket API简介
不同计算机(通过网络相连)上运行的进程相互通信机制称为网络进程间通信(network IPC)。在本地可以通过进程PID来唯一标识一个进程,但是在网络中这是行不通的。其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“
ip地址”可以唯一标识网络中的主机,而传输层的“
协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(
ip地址,协议,端口)构成套接字,就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。套接字是通信端口的抽象!通过套接字网络IPC接口,进程能够使用该接口和其他进程通信。部分参考:UNIX环境高级编程中文第二版PDF高清版 下载地址 http://www.linuxidc.net/thread-2063-1-1.htmlUnix环境高级编程 源代码地址 http://www.linuxidc.com/Linux/2011-04/34826.htmUnix环境高级编程源码编译 http://www.linuxidc.com/Linux/2011-09/42503.htm
apue.h头文件(Unix环境高级编程) http://www.linuxidc.com/Linux/2012-01/51729.htm《Unix环境高级编程》(第二版)apue.h的错误 http://www.linuxidc.com/Linux/2011-04/34662.htmUnix环境高级编程第二版读书笔记 http://www.linuxidc.com/Linux/2011-04/34235.htm《Unix环境高级编程》中apue.h的问题 http://www.linuxidc.com/Linux/2013-01/77686.htm
几个定义:- IP地址:即依照TCP/IP协议分配给本地主机的网络地址,两个进程要通讯,任一进程首先要知道通讯对方的位置,即对方的IP。
- 端口号:用来辨别本地通讯进程,一个本地的进程在通讯时均会占用一个端口号,不同的进程端口号不同,因此在通讯前必须要分配一个没有被访问的端口号。
- 连接:指两个进程间的通讯链路。
- 半相关:网络中用一个三元组可以在全局唯一标志一个进程:(协议,本地地址,本地端口号)这样一个三元组,叫做一个半相关,它指定连接的每半部分。
- 全相关:一个完整的网间进程通信需要由两个进程组成,并且只能使用同一种高层协议。也就是说,不可能通信的一端用TCP协议,而另一端用UDP协议。因此一个完整的网间通信需要一个五元组来标识:(协议,本地地址,本地端口号,远地地址,远地端口号),这样一个五元组,叫做一个相关(association),即两个协议相同的半相关才能组合成一个合适的相关,或完全指定组成一连接。
套接字描述符
套接字是端点的抽象。与应用进程要使用文件描述符访问文件一样,访问套接字也需要用套接字描述符。套接字描述符在UNIX系统中是用文件描述符实现的。要创建一个套接字,可以调用socket函数。
| 12 | #include<sys/socket.h>int socket(int domain, int type, int protocol); |
参数:作用:socket()用于创建一个socket描述符(socket descriptor),它唯一标识一个socket。
网络字节序
网络协议指定了字节序,因此异构计算机系统能够交换协议信息而不会混淆字节序。TCP/IP协议栈采用大端字节序。应用进程交换格式化数据时,字节序问题就会出现。对于TCP/IP,地址用网络字节序来表示,所以应用进程有时需要在处理器的字节序与网络字节序之间转换。
| 12345 | #include<arpa/inet.h>uint32_t htonl(uint32_t hostlong);uint16_t htons(uint16_t hostshort);uint32_t ntohl(uint32_t netlong);uint16_t ntohs(uint16_t netshort); |
这些函数名很好记,h表示host,n表示network, l表示32位长整数,s表示16位短整数在将一个地址绑定到socket的时候,请先将主机字节序转换成为网络字节序,对主机字节序不要做任何假定,务必将其转化为网络字节序再赋给socket!
将套接字与地址绑定
与客户端的套接字关联的地址意义不大,可以让系统选择一个默认的地址。然而,对于服务器,需要给一个接收客户端请求的套接字绑定一个众所周知的地址。客户端应有一种方法用以连接服务器的地址,最简单的方法就是为服务器保留一个地址并且在/etc/services或某个名字服务(name service)中注册。 可以用bind函数来搞定这个问题:
| 123 | #include <sys/types.h> #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); |
参数:第一个参数:bind()函数把一个地址族中的特定地址赋给该sockfd(套接字描述字)。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。 第二个参数:struct sockaddr *指针,指向要绑定给sockfd的协议地址。这个地址结构根据地址创建socket时的地址协议族的不同而不同:
地址格式
地址标识了特定通信域中的套接字端点,地址格式与特定的通信域相关。为使不同格式地址能够被传入到套接字函数,地址需被强转为通用的地址结构sockaddr表示。struct sockaddr 是一个通用地址结构,该结构定义如下: | 12345 | struct sockaddr{ sa_family_t sa_family; char sa_data[14];} |
IPV4因特网域:| 123456789101112 | struct in_addr { uint32_t s_addr; }; struct sockaddr_in { sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; }; |
IPv6因特网域:| 1234567891011121314 | struct in6_addr { unsigned char s6_addr[16]; }; struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; }; |
Unix域对应的是: | 1234567 | #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; char sun_path[UNIX_PATH_MAX]; }; |
第三个参数:addrlen 对应的是地址的长度
返回值:成功返回0,出错返回-1
作用:将套接字与端口号绑定,即把一个ip地址和端口号组合赋给socket
更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2016-08/134307p2.htm