【RL-TCPnet网络教程】第18章 BSD Sockets基础知识

第18章      BSD Sockets基础知识

本章节为你们讲解BSD Sockets,须要你们对BSD Sockets有个基础的认识,方便后面章节Socket实战操做。程序员

(本章的知识点主要整理自网络)编程

18.1  初学者重要提示服务器

18.2  Socket基础知识参考资料网络

18.3  Socket基础知识点数据结构

18.4  BSD Sockets简介dom

18.5  BSD Sockets的API说明socket

18.6  总结编程语言

 

18.1  初学者重要提示

    初学者务必要对Socket的基础知识点有个认识,不是特别理解没有关系,随着后面逐渐的实战操做,会有比较全面的认识。函数

 

18.2  Socket基础知识参考资料

首次搞Socket,须要对Socket的一些基础知识有个了解。你们能够从如下地址得到Socket基础知识,下面是Socket参考资料:学习

下面是BSD Sockets参考资料:

对于初学者来讲,学习上面六个参考资料就够了。若是你们有网络方面的书籍,好比《TCP/IP详解》,也能够直接看书籍。

 

18.3  Socket基础知识点

(这里的知识点整理自上面的参考资料地址)

教程这里也对Socket的基础知识作个介绍,方便你们快速上手操做。

18.3.1 网络套接字(Network Socket)

在计算机科学中,网络套接字,又译网络接口、网络插槽,是电脑网络中进程间数据流的端点。使用以网际协议IP为通讯基础的网络套接字,称为网际套接字Internet Socket。由于网际协议的流行,现代绝大多数的网络套接字,都是属于网际套接字。

Socket是一种操做系统提供的进程间通讯机制。Socket最初被翻译为 “媒介(字)”。不久,ARPANET的Socket就被翻译为“套接字”,其理由是:

因为每一个主机系统都有各自命名进程的方法,并且经常是不兼容的,所以,要在全网范围内硬把进程名字统一块儿来是不现实的。因此,每一个计算机网络中都要引入一种起媒介做用的、全网一致的标准名字空间。这种标准名字,在ARPA网中称做套接字,而在不少其余计算机网中称做信口。更确切地说,进程之间的链接是经过套接字或信口构成的。

在操做系统中,一般会为应用程序提供一组应用程序接口,称为套接字接口(Socket API)。应用程序能够经过套接字接口,来使用网络套接字,以进行数据交换。最先的套接字接口来自于4.2 BSD,所以现代常见的套接字接口大多源自Berkeley套接字(Berkeley Sockets)标准。

------------------------------------------

网络上的两个程序经过一个双向的通讯链接实现数据的交换,这个链接的一端称为一个Socket。创建网络通讯链接至少要一对端口号(Socket)。Socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员作网络开发所用的接口,这就是Socket编程接口。HTTP是轿车,提供了封装或者显示数据的具体形式,Socket是发动机,提供了网络通讯的能力。

Socket的英文原义是“孔”或“插座”。做为BSD UNIX的进程通讯机制,取后一种意思。一般也称做"套接字",用于描述IP地址和端口,是一个通讯链的句柄,能够用来实现不一样虚拟机或不一样计算机之间的通讯。在Internet上的主机通常运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不一样的端口对应于不一样的服务。Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各类插座的房间,每一个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。客户软件将插头插到不一样编号的插座,就能够获得不一样的服务。

 

18.3.2 Socket形象解释

Socket很是相似于电话插座。以一个国家级电话网为例,电话的通话双方至关于相互通讯的2个进程,区号是它的网络地址;区内一个单位的交换机至关于一台主机,主机分配给每一个用户的局内号码至关于Socket号。任何用户在通话以前,首先要占有一部电话机,至关于申请一个Socket;同时要知道对方的号码,至关于对方有一个固定的Socket。而后向对方拨号呼叫,至关于发出链接请求(假如对方不在同一区内,还要拨对方区号,至关于给出网络地址)。假如对方在场并空闲(至关于通讯的另外一主机开机且能够接受链接请求),拿起电话话筒,双方就能够正式通话,至关于链接成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,至关于向Socket发送数据和从Socket接收数据。通话结束后,一方挂起电话机至关于关闭Socket,撤消链接。

在电话系统中,通常用户只能感觉到本地电话机和对方电话号码的存在,创建通话的过程,话音传输的过程以及整个电话系统的技术细节对他都是透明的,这也与Socket机制很是类似。Socket利用网间通讯设施实现进程通讯,但它对通讯设施的细节绝不关心,只要通讯设施能提供足够的通讯能力,它就知足了。

至此,咱们对Socket进行了直观的描述。抽象出来,Socket实质上提供了进程通讯的端点。进程通讯以前,双方首先必须各自建立一个端点,不然是没有办法创建联系并相互通讯的。正如打电话以前,双方必须各自拥有一台电话机同样。

在网间内部,每个Socket用一个半相关描述(协议,本地地址,本地端口)。一个完整的Socket有一个本地惟一的Socket号,由操做系统分配。最重要的是,Socket是面向客户/服务器模型而设计的,针对客户和服务器程序提供不一样的Socket系统调用。客户随机申请一个Socket(至关于一个想打电话的人能够在任何一台入网电话上拨号呼叫),系统为之分配一个Socket号;服务器拥有全局公认的Socket,任何客户均可以向它发出链接请求和信息请求(至关于一个被呼叫的电话拥有一个呼叫方知道的电话号码)。

Socket利用客户/服务器模式巧妙地解决了进程之间创建通讯链接的问题。服务器Socket半相关被全局所公认很是重要。你们不妨考虑一下,两个彻底随机的用户进程之间如何创建通讯?假如通讯双方没有任何一方的Socket固定,就比如打电话的双方彼此不知道对方的电话号码,要通话是不可能的。

 

18.3.3 Sockets链接过程

根据链接启动的方式以及本地套接字要链接的目标,套接字之间的链接过程能够分为三个步骤:服务器监听,客户端请求,链接确认。

(1)    服务器监听:是服务器端套接字并不定位具体的客户端套接字,而是处于等待链接的状态,实时监控网络状态。

(2)    客户端请求:是指由客户端的套接字提出链接请求,要链接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要链接的服务器的套接字,指出服务器端套接字的地址和端口号,而后就向服务器端套接字提出链接请求。

(3)    链接确认:是指当服务器端套接字监听到或者说接收到客户端套接字的链接请求,它就响应客户端套接字的请求,创建一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,链接就创建好了。而服务器端套接字继续处于监听状态,继续接收其余客户端套接字的链接请求。

大致流程图以下:

18.4 Windows Sockets简介

Windows Sockets是Windows下获得普遍应用的、开放的、支持多种协议的网络编程接口。从1991年的1.0版,通过不断完善并在Intel、Microsoft、Sun、SGI、Informix、Novell等公司的全力支持下,已成为Windows网络编程的事实上的标准。

Windows Sockets规范以U.C.Berkeley大学BSD UNIX中流行的Socket接口为范例定义了一套Microsoft Windows下网络编程接口。它不只包含了人们所熟悉的BerkeleySocket风格的库函数;也包含了一组针对Windows的扩展库函数,以使程序员能充分地利用Windows消息驱动机制进行编程。WindowsSockets规范本意在于提供给应用程序开发者一套简单的API,并让各家网络软件供应商共同遵照。此外,在一个特定版本Windows的基础上,WindowsSockets也定义了一个二进制接口(ABI),以此来保证应用WindowsSocketsAPI的应用程序可以在任何网络软件供应商的符合WindowsSockets协议的实现上工做。所以这份规范定义了应用程序开发者可以使用,而且网络软件供应商可以实现的一套库函数调用和相关语义。遵照这套WindowsSockets规范的网络软件,咱们称之为WindowsSockets兼容,而WindowsSockets兼容实现的提供者,咱们称之为WindowsSockets提供者。一个网络软件供应商必须百分之百地实现WindowsSockets规范才能作到WindowsSockets兼容。任何可以与WindowsSockets兼容实现协同工做的应用程序就被认为是具备WindowsSockets接口。咱们称这种应用程序为WindowsSockets应用程序。WindowsSockets规范定义并记录了如何使用API与Internet协议族(IPS,一般咱们指的是TCP/IP)链接,尤为要指出的是全部的WindowsSockets实现都支持流套接字接口和数据报套接字接口,应用程序调用WindowsSockets的API实现相互之间的通信。WindowsSockets又利用下层的网络通信协议功能和操做系统调用实现实际的通信工做。

 

18.5 BSD Sockets简介

Berkeley sockets,又称BSD sockets,是一种应用程序接口,用于网际套接字和Unix域套接字(Unix domain sockets),包括了一个用C语言写成的应用程序开发库,主要用于实现进程间通信。BSD Sockets能够在不少不一样的输入/输出设备和驱动之上运行,尽管这有赖于操做系统的具体实现。接口实现用于TCP/IP协议,所以它是维持Internet的基本技术之一。它是由加利福尼亚的伯克利大学开发,最初用于Unix系统。 现在,全部的现代操做系统都有一些源于Berkeley套接字接口的实现,它已成为链接Internet的标准接口。

BSD Sockets刚开始是4.2BSD Unix操做系统(于1983发布)的一套应用程序接口。然而,因为AT&T的专利保护着Unix,因此只有在1989年伯克利大学才能自由地发布本身的操做系统和网络库。

Berkeley套接字应用程序接口造成了事实上的网络套接字的标准精髓。大多数其余的编程语言使用与这套用C语言写成的应用程序接口相似的接口。这套应用程序接口也被用于Unix域套接字。

 

18.5.1 使用BSD Sockets的系统

因为Berkeley套接字是第一个socket,大多数程序员很熟悉它们,因此大量系统把伯克利套接字做为其主要的网络API,好比下面四个:

  • Windows Sockets (Winsock) ,和Berkeley Sockets很类似,最初是为了便于移植Unix程序。
  • Java Sockets
  • Python sockets
  • Perl sockets

 

18.5.2 BSD Sockets的头文件

    Berkeley套接字接口的定义在几个头文件中。这些文件的名字和内容与具体的实现之间有些许的不一样。 大致上包括:
<sys/socket.h>
    BSD套接字核心函数和数据结构。
    AF_INET、AF_INET6 地址集和它们相应的协议集PF_INET、PF_INET6。 普遍用于Internet,这些包括了IP地址和TCP、UDP端口号。
<netinet/in.h>
    AF_INET 和AF_INET6 地址家族和他们对应的协议家族 PF_INET 和 PF_INET6。在互联网编程中普遍使用,包括IP地址以及TCP和UDP端口号。(有待查阅,跟socket.h的功能说明重复了
<sys/un.h>
    PF_UNIX/PF_LOCAL 地址集。用于运行在一台计算机上程序间的本地通讯,不用于网络通信。
<arpa/inet.h>
   处理数值型IP地址的函数。
<netdb.h>
    将协议名和主机名翻译为数值地址的函数,搜索本地数据以及DNS。

 

18.5.3 BSD Sockets的API函数

这个列表是BSD Sockets API库提供的函数概要(这里的介绍,有个了解便可,下一章节会专门讲解RL-TCPnet提供的Socket API):

socket() 
    建立一个新的肯定类型的套接字,类型用一个整型数值标识(文件描述符),并为它分配系统资源。
bind() 
    通常用于服务器端,将一个套接字与一个套接字地址结构相关联,好比,一个指定的本地端口和IP地址。
listen() 
    用于服务器端,使一个绑定的TCP套接字进入监听状态。
connect() 
    用于客户端,为一个套接字分配一个自由的本地端口号。若是是TCP套接字的话,它会试图得到一个新的TCP链接。
accept() 
    用于服务器端。它接收一个从TCP客户端发出的链接请求并建立一个新的套接字,并与该链接相应的套接字地址相关联。
send()和recv(),或者write()和read(),或者recvfrom()和sendto(), 
    用于套接字的数据收发。
close() 
    用于释放套接字资源。若是是TCP,链接会被中断。
gethostbyname()和gethostbyaddr()
    用于解析主机名和地址。
select() 
    用于修整有以下状况的套接字列表:准备读,准备写或者有错误。
poll() 
    用于检查套接字的状态。套接字能够被测试,看是否能够写入、读取或是有错误。
getsockopt() 
    用于查询指定的套接字中一个特定的套接字选项的当前值。
setsockopt() 
    用于为指定的套接字设定一个特定的套接字选项。

 

18.5.4 BSD Sockets支持的协议

套接字API是Unix网络的通用接口,容许使用各类网络协议和地址。下面列出了BSD Sockets支持的协议,如今的 Linux 和 BSD 中通常都已经实现了。

PF_LOCAL, PF_UNIX, PF_FILE  Local to host (pipes and file-domain)

PF_INET                     IP protocol family

PF_AX25                     Amateur Radio AX.25

PF_IPX                      Novell Internet Protocol

PF_APPLETALK                Appletalk DDP

PF_NETROM                   Amateur radio NetROM

PF_BRIDGE                   Multiprotocol bridge

PF_ATMPVC                   ATM PVCs

PF_X25                      Reserved for X.25 project

PF_INET6                    IP version 6

PF_ROSE                     Amateur Radio X.25 PLP

PF_DECnet                   Reserved for DECnet project

PF_NETBEUI                  Reserved for 802.2LLC project

PF_SECURITY                 Security callback pseudo AF

PF_KEY                      PF_KEY key management API

PF_NETLINK, PF_ROUTE        routing API

PF_PACKET                   Packet family

PF_ASH                      Ash

PF_ECONET                   Acorn Econet

PF_ATMSVC                   ATM SVCs

PF_SNA                      Linux SNA Project

PF_IRDA                     IRDA sockets

PF_PPPOX                    PPPoX sockets

PF_WANPIPE                  Wanpipe API sockets

PF_BLUETOOTH                Bluetooth sockets

 

18.6 BSD Sockets的API说明

说明:这些知识点整理自wiki中文

这里主要将几个主要的BSD Sockets API作个介绍(这里的介绍,有个了解便可,下一章节会专门讲解RL-TCPnet提供的Socket API):

18.6.1 函数socket

函数原型:

int socket(int domain, int type, int protocol);

函数描述:

socket() 为通信建立一个端点,为套接字返回一个文件描述符。socket() 有三个参数:

  • 第1个参数domain 为建立的套接字指定协议集(或称作地址族 address family)。 例如:

        AF_INET 表示IPv4网络协议。

        AF_INET6 表示IPv6。

        AF_UNIX 表示本地套接字(使用一个文件)。

  • 第2个参数type(socket类型) 以下:

        SOCK_STREAM (可靠的面向流服务或流套接字)。

        SOCK_DGRAM (数据报文服务或者数据报文套接字)。

        SOCK_SEQPACKET (可靠的连续数据包服务)。

        SOCK_RAW (在网络层之上自行指定运输层协议头,即原始套接字)。

  • 第3个参数protocol 指定实际使用的传输协议。 最多见的就是IPPROTO_TCP、IPPROTO_SCTP、IPPROTO_UDP、IPPROTO_DCCP。这些协议都在<netinet/in.h>中有详细说明。 若是该项为“0”的话,即根据选定的domain和type选择使用缺省协议。
  • 返回值,若是发生错误,函数返回值为-1。不然,函数会返回一个表明新分配的描述符的整数。

 

18.6.2 函数bind

函数原型: 

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

函数描述:

bind() 为一个套接字分配地址。当使用socket()建立套接字后,只赋予其所使用的协议,并未分配地址。在接受其它主机的链接前,必须先调用bind()为套接字分配一个地址。bind()有三个参数:

  • 第1个参数sockfd, 表示使用bind函数的套接字描述符。
  • 第2个参数my_addr, 指向sockaddr结构体(用于表示所分配地址)的指针变量。
  • 第3个参数addrlen, 用socklen_t字段指定了sockaddr结构的长度。
  • 返回值,若是发生错误,函数返回值为-1,不然为0。

 

18.6.3 函数listen()

函数原型: 

int listen(int sockfd, int backlog);

函数描述:

当socket和一个地址绑定以后,listen()函数会开始监听可能的链接请求。然而,这只能在有可靠数据流保证的时候使用,例如:数据类型(SOCK_STREAM, SOCK_SEQPACKET)。

listen()函数须要两个参数:

  • 第1个参数sockfd, 表示socket的描述符。
  • 第2个参数backlog, 表示监听队列大小,当有一个链接请求到来,就会进入此监听队列;当一个链接请求被accept()接受,则从监听队列中移出;当队列满后,新的链接请求会返回错误。
  • 返回值,一旦链接被接受,返回0表示成功,错误返回-1。

 

18.6.4 函数accept()

函数原型: 

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

函数描述:

当应用程序监听来自其余主机的数据流链接时,经过事件(好比Unix select()系统调用)通知它。必须用 accept()函数初始化链接。Accept() 为每一个链接创立新的套接字并从监听队列中移除这个链接。它使用以下参数:

  • 第1个参数sockfd,监听的套接字描述符。
  • 第2个参数cliaddr,指向sockaddr 结构体的指针,客户机地址信息。
  • 第3个参数addrlen,指向 socklen_t的指针,肯定客户机地址结构体的大小 。
  • 返回值,返回新的套接字描述符,出错返回-1。进一步的通讯必须经过这个套接字。

Datagram 套接字不要求用accept()处理,由于接收方可能用监听套接字当即处理这个请求。

 

18.6.5 函数connect()

函数原型: 

int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen);

函数描述:

函数connect用于配置要链接的远程IP地址和端口, 返回-1表示出错,0表示成功。

 

18.6.6 函数gethostbyname()

函数原型: 

struct hostent *gethostbyname(const char *name);

 函数描述:

gethostbyname()函数是用来解析主机名。可能会使用DNS或者本地主机上的其余解析机制。返回一个指向 struct hostent的指针,这个结构体描述一个IP主机。

函数gethostbyname使用以下参数:

  • name 指定主机名,例如 www.armfly.com
  • 出错返回NULL指针,能够经过检查 h_errno 来肯定是临时错误仍是未知主机。正确则返回一个有效的 struct hostent *。

注意:这个函数并非BSD Sockets严格的组成部分。这个函数多是过期了,新函数是getnameinfo(), 这个函数是基于addrinfo数据结构。

 

18.6.7 函数gethostbyaddr

函数原型: 

struct hostent *gethostbyaddr(const void *addr, int len, int type);

 

函数描述:

gethostbyaddr()函数是用来解析主机名和地址的。可能会使用DNS或者本地主机上的其余解析机制。返回一个指向 struct hostent的指针,这个结构体描述一个IP主机。

函数gethostbyname使用以下参数:

  • addr 指向 struct in_addr的指针,包含主机的地址。
  • len 给出 addr的长度,以字节为单位。
  • type 指定地址族类型 (好比 AF_INET)。
  • 返回值,出错返回NULL指针,能够经过检查 h_errno 来肯定是临时错误仍是未知主机。正确则返回一个有效的 struct hostent *。

注意:这个函数并非BSD Socket严格的组成部分。这个函数多是过期了,新函数是 getaddrinfo(),这个新函数是基于addrinfo数据结构。

 

18.7 总结

本章节就为你们讲解这么多,更多BSD Sockets的相关知识须要你们查阅相关书籍进行学习,或者网上搜索相关资料进行学习。

相关文章
相关标签/搜索