网络中的进程是如何通讯的?html
在网络中进程之间进行通讯的时候,那么每一个通讯的进程必须知道它要和哪一个计算机上的哪一个进程通讯.不然通讯无从谈起!在本地能够经过进程PID来惟一标识一个进程,可是在网络中这是行不通的.其实TCP/IP协议族已经帮咱们解决了这个问题,网络层的“ip地址”能够惟一标识网络中的主机,而传输层的“协议+端口”能够惟一标识主机中的应用程序(进程).这样利用三元组(ip地址,协议,端口)就能够标识网络的进程了,网络中的进程通讯就能够利用这个标志与其它进程进行交互.linux
什么是套接字?数据库
套接字是做为4BDS UNIX的进程通讯机制,它用于描述 IP 地址和端口,是一个用于通讯链接的文件描述符.举个例子来讲.套接字就好像是银行的服务窗口.而后每一个服务窗口上面都有一个标号(对应套接字的 IP 地址),而后银行又有规定标号为多少的窗口提供什么服务,标号为窗口提供什么服务(窗口标号就相似套接字中记录的 IP 地址,服务就相似着套接字的端口号),那么客户就能够根据这个窗口标号去请求所须要的服务.编程
在 socket 中是怎么作到对另外一个套接字链接的缓存
首先很明显,上面一直在强调两个进程在进行与网络通讯的时候,两个进程都必须知道对方是谁(经过"ip地址+端口"),不然就没法进行通讯,能够设想下你写了封信给你的朋友小明,那么你忘了写寄信地址和寄信人.那么你把这份信寄了.而后你就开始等待小明的回信,那么小明就算收到信了也不知道这封信是谁寄的和该把回复信寄给谁.那么你能收到回信么?安全
可是有时候你在写通讯时候好比 tcp 的客户端,你发现你没有对套接字进行地址绑定也依旧能够和服务器通讯,那这又是为何?由于操做系统帮你作了这件事,操做系统在发现你没有将一个套接字绑定到对应的 ip 地址和端口号而调用 listen 和connect 的时候.那么它会自动给你分配 IP 地址和端口号.接着上面那个寄信的例子,假设你在寄信的时候是托给个朋友帮你寄.那么这个好心的朋友发现了你犯的这个粗心的错误.那么他便把在寄信人和寄信地址处填写上了你的名字和你的地址,那么小明就能够和你正常通讯了.服务器
既然这为何服务器还要大费周章的去对一个监听端口进行地址绑定呢?咱们仍是用上面那个寄信的例子来讲,假设你颇有钱,有三套房子(即服务器对应三个 IP),你依旧没有写寄信人和寄信地址.那么你虽然托朋友给你寄,可是你这个朋友也不肯定你如今住那套房子里,那么他便把这个三个地址之中的一个地址填了上去.而偏偏很不幸的是你已近好久没有住那套房子了.那么小明即便回复了你的信,你也可能收不到信了.因此服务器必需要对监听套接字进行地址进行绑定!网络
什么是大小端架构
由于计算机内存是以字节(八位)为单位来存储东西的.那么在存储大于一字节的数据时候就会存在一个问题,按什么样的顺序去存放这样的数据,是低位字节排放在内存的低地址端仍是低位字节排放在内存的高地址端.然而这个每每和具体CPU架构有关,而非操做系统.那么首先咱们来讲明下大端模式和小端模式的区别:socket
这样也许很差理解那么举个例子来讲.若是将一个 16 位的整数 0x1234 存放到一个短整型变量(short)中,这个短整型变量采用大端或者小端模式在内存中的存储由下表所示.
socket 中的 tcp 编程的大体流程
注意问题
地址结构体
struct in_addr{in_addr_t s_addr;}; struct sockaddr_in{ sa_family_t sin_family; in_port_t sin_port; struct in_addr sin_addr; };
struct in6_addr{ sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; };
地址查询
经过调用 gethostent 获取主机信息,当 gethostent 返回时,获得一个指向 hostent 结构体指针,该结构体可能包含一个静态的数据缓存区,每次调用 gethostlent 将会覆盖这个缓存区.返回的地址采用网络字节序.相关函数:
相关结构体:
struct hostent{ char *h_name; char **h_aliases; char h_addrtype; char h_length; char **h_addr_list; ... };
将协议名字和协议号采用如下函数映射
相关函数
相关结构体
struct protoent{ char* p_name; char** p_aliases; int p_proto; }
服务查询
服务是由地址的端口号部分表示的.每一个服务由惟一的熟知的端口号来提供,采用函数 getservbyname 能够将一个服务名字映射到一个端口号,函数getservbyport将一个端口号映射到一个服务器名,或者采用函数 getservent顺序扫描服务数据库.相关函数:
struct servent{ char *s_name; char **s_aliases; int s_port; cjar *s_proto; };
套接字的经常使用 API
参考资料