彻底弄懂套接字

这篇具有很好参考价值的文章主要介绍了彻底弄懂套接字。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.什么是套接字(英文名:插座)

        套接字(socket)是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。Linux所提供的功能(如打印服务、连接数据库和提供Web页面)和网络工具(如用于远程登录的rlogin和用于文件传输的ftp)通常都是通过套接字来进行通信的。

        套接字的创建和使用与管道是有区别的,因为套接字明确地将客户和服务器区分开来。套接字机制可以实现将多个客户连接到一个服务器。

2.套接字的域

      指定套接字通信中使用的网络介质。最常见的套接字域是AF_INET,它指的是Internet网络,许多Linux局域网使用的都是该网络,当然,因特网自身用的也是它。其底层的协议——网际协议(IP)只有一个地址族,它使用一种特定的方式来指定网络中的计算机,即人们常说的IP地址。

3.套接字类型

        一个套接字域可能有多种不同的通信方式,而每种通信方式又有其不同的特性。但AF_UNIX域的套接字没有这样的问题,它们提供了一个可靠的双向通信路径。在网络域中,我们就需要注意底层网络的特性,以及不同的两种通信机制:流(stream)数据报(datagram)。它们有着截然不同的服务层次。

 (1)流套接字

                流套接字(在某些方面类似于标准的输入/输出流)提供的是一个有序、可靠、双向字节流的连接。因此,发送的数据可以确保不会丢失、复制或乱序到达,并且在这一过程中发生的错误也不会显示出来。大的消息将被分片、传输、再重组。这很像一个文件流,它接收大量的数据,因为它们在编写网络程序时是最常用的。

                TCP/IP代表的是传输控制协议/网际协议。IP协议是针对数据包的底层协议,它提供从一台计算机通过网络到达另一台计算机的路由。TCP协议提供排序,流控和重传,以确保大数据的传输可以完整地到达目的地或报告一个适当的错误条件。

(2)数据报套接字

                与流套接字相反,由类型SOCK_DGRAM指定的数据报套接字不建立和维持一个连接。它对可以发送的数据报的长度有限制。数据报作为一个单独的网络消息被传输,它可能会丢失、复制或乱序到达。

                数据报套接字是在AF_INET域中通过UDP/IP连接实现的,它提供的是一种无序的不可靠服务(UDP代表的是用户数据报协议)。但从资源的角度来看,相对来说它们开销比较小,因为不需要维持网络连接。而且因为无需花费时间来建立连接,所以它们的速度也很快。

                数据报适用于信息服务中“单次”(singl-shot)查询,它主要用来提供日常状态信息或执行低优先级的日志记录。它的优点是服务器的崩溃不会给客户造成不便,也不会要求客户重启,因为基于数据报的服务器通常不保留连接信息,所以它们可以在不打扰其客户的前提下停止并重启。

4.套接字协议

        只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。那么这里提供了UNIX网络套接字文件系统套接字,它们不需要你选择一个特定的协议,只需要使用其默认值即可。(这里将不详细讨论这两种)

5.创建套接字

        socket系统调用创建一个套接字并返回一个描述符,该描述符可以用来访问该套接字。

#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain,int protocol);

        创建的套接字是一条通信线路的一个端点,domain参数指定协议族,type参数指定这个套接字的通信类型,protocol参数指定使用的协议。             

        domain参数可以指定的协议族如下图:

  套接字,网络编程,服务器,网络,linux

        最常见的套接字域是AF_UNIX和AF_INET,前者用于通过UNIX和Linux文件系统实现的本地套接字,后者用于UNIX网络套接字。AF_INET套接字可以用于通过包括因特网在内的TCP/IP网络进行通信的程序。微软Windowns系统的Windowns接口也提供了对这个套接字域的访问功能。

        socket函数的参数type指定用于新套接字的通信特性。它的取值包括SOCK_STREAM和SOCK_DGRAM。

        SOCK_STREAM是一个有序、可靠、面向连接 的双向字节流,对AF_INET域套接字来说,它默认是通过一个TCP连接来提供这一特性的,TCP连接在两个流套接字端点之间建立。数据可以通过套接字连接进行双向传递。TCP协议所提供的机制可以用于分片和重组长消息,并且可以重传可能在网络中丢失的数据。        

        socket系统调用返回一个描述符,它在许多方面都类似于底层的文件描述符。当这个套接字连接到另一端的套接字后,我们就可以用read和write系统调用,通过这个描述符来在套接字上发送和接收数据了。close系统调用用于结束套接字连接。

6.套接字地址

        每个套接字域都有其自己的地址格式。对于AF_UNIX域套接字来说,它的地址由结构sockaddr_un来描述,该结构定义在头文件sys/un.h中。

struct sockaddr_un{
    sa_family_t    sun_family;    /* AF_UNIX */
    char           sun_path[];    /* pathname */
};

        因此,对套接字进行处理的系统调用可能需要接受不同类型的地址,每种地址格式都使用一种类似的结构来描述,它们都以一个指定地址类型(套接字域)的成员(在本例中是sun_family)开始。在AF_UNIX域中,套接字地址由结构中的sun_path成员中的文件名所指定。

        在当前的Linux系统中,由X/Open规范定义的类型sa_family_t在头文件sys/un.h中声明,它是短整型。此外,sun_path指定的路径名长度也是有限制的(Linux规定的是108个字符,其他系统可能使用的是更清楚的常量,如UNIX_MAX_PATH)。因为地址结构的长度不一致,所以许多套接字调用需要用到一个用来复制特定地址结构的长度变量或将它作为一个输出。

        在AF_INET域中,套接字地址由结构sockaddr_in来指定,该结构定义在头文件netinet/in.h中,它至少包含以下几个成员:

struct sockaddr_in{
    short int                sin_family;        /* AF_INEX */
    unsigned short int       sin_port;          /* Port number */
    struct in_addr           sin_addr;          /* Internet address */      
};

 IP地址结构in_addr被定义为:

struct  in_addr{
    unsigned  long  int      s_addr;
};

 IP地址中的4个字节组成一个32位的值。一个AF_INET套接字由它的域、IP地址和端口号来完全确定。从应用程序的角度来看,所有套接字的行为就像文件描述符一样,并且通过一个唯一的整数值来区分。

7.命名套接字

        要想让通过sockket调用创建的套接字可以被其他进程使用,服务器程序就必须给该套接字命名。这样,AF_UNIX套接字就会关联到一个文件系统的命名。

#include <sys/socket.h>

int bind(int socket, const struct sockaddr *address, size_t address_len);

         bind系统调用把参数address中的地址分配给文件描述符socket关联的未命名套接字。地址结构的长度由参数address_len传递。

        地址的长度和格式取决于地址族。bind调用需要将一个特定的地址结构指针转换为指向通用地址类型(struct sockaddr *)。

        bind调用在成功时返回0,失败时返回-1并设置errno为下表中的一个值。

套接字,网络编程,服务器,网络,linux

AF_UNIX域套接字还有其他一些错误代码,如下表。 

套接字,网络编程,服务器,网络,linux

 8.创建套接字队列

        为了能够在套接字上接受进入的连接,服务器程序必须创建一个队列来保存未处理的请求。它用listen系统调用来完成这一工作。

#include <sys/socket.h>

int listen(int socket, int backlog);

         Linux系统可能会对队列中可以容纳的未处理连接的最大数目做出限制。为了遵守这个最大值限制,listen函数将队列长度设置为backlog参数的值。在套接字队列中,等待处理的进入连接的个数最多不能超过这个数字。再往后的连接将被拒绝,导致客户的连接请求失败。listen函数提供的这种机制允许当服务器程序正忙处理前一个客户请求的时候,将后续的客户连接放入队列等待处理。backlog参数常用的值为5.

        listen函数在成功时返回0,失败时返回-1.错误代码包括EBADF、EINVAL和ENOTSOCK,其含义与上面bind系统调用中说明的一样。

9.接受连接

        一旦服务器程序创建并命名了套接字之后,它就可以通过accept系统调用来等待客户建立对该套接字的连接。

#include <sys/socket.h>

int accept(int socket, struct sockaddr *address, size_t *address_len);

         accept系统调用只有当有客户程序试图连接到由socket参数指定的套接字上时才返回。这里的客户是值在套接字队列中排第一个的未处理连接。accept函数将创建一个新套接字来与该客户进行通信,并且返回新套接字的描述符。新套接字的类型和服务器监听套接字类型一样的。

        套接字必须事先由bind调用命名,并且由listen调用给它分配一个连接队列。连接客户的地址将被放入address参数指向的sockaddr结构中。如果我们不关心客户的地址,也可以将address参数指定为空指针。

        参数addr_len指定客户结构的长度。如果客户地址的长度超过这个值,它将被截断。所以在调用accept之前,address_len必须被设置为预期的地址长度。当这个调用返回时,address_len将被设置为连接客户地址结构的实际长度。

        如果套接字队列中没有未处理的连接,accept将阻塞(程序将1暂停)直到有客户建立连接为止。我们可以通过对套接字文件描述符设置O_NONBLOCK标志来改变这一行为,使用的函数是fcnt1,如下:

int flags = fcnt1(socket, F_GETFL, 0);

fcnt1(socket, F_SETFL, O_NONBLOCK|flags);

         当有未处理的客户连接时,accept函数将返回一个新的套接字文件描述符。发生错误时,accept函数将返回-1,可能的错误情况大部分与bind、listen调用类似,其他的错误有EWOULDBLOCK和EINTR。前者是当指定了O_NONBLOCK标志,但队列中没有未处理连接时产生的错误。后者是当进程阻塞在accept调用时,执行被中断而产生的错误。

10.请求连接

        客户程序通过在一个未命名套接字和服务器监听套接字之间建立连接的方法来连接到服务器。它们通过connect调用来完成这一工作。

#include <sys/socket.h>

int connect(int socket, const struct sockaddr *address, size_t address_len);

         参数socket指定的套接字将连接到参数address指定的服务器套接字,address指向的结构的长度由参数address_len指定。参数socket指定的套接字必须是通过socket调用获得的一个有效的文件描述符。

        成功时,connect调用返回0,失败时返回-1.可能的错误代码见下表。

套接字,网络编程,服务器,网络,linux

         如果连接不能立刻建立,connect调用将阻塞一段不确定的超时时间。一旦这个超时时间到达,连接将被放弃,connect调用失败。但如果connect调用被一个信号中断,而该信号又得到了处理,connect调用还是会失败(errno被设置为EINTR),但连接尝试并不会被放弃,而是以异步方式继续建立,程序必须在此后进行检查以查看连接是否成功建立。

        与accept调用一样,connect调用的阻塞特性可以通过设置该文件描述符的O_NONBLOCK标志来改变。此时,如果连接不能立刻建立,connect将失败并把errno设置为EINPROGRESS,而连接将以异步方式继续进行。

        虽然异步连接难于处理,但我们可以在套接字文件描述符上用select调用来检查套接字是否已处于就绪状态。(此处先不将select调用)

11.关闭套接字

        你可以通过调用close函数来终止服务器和客户上的套接字连接,就如同对底层文件描述符进行关闭一样。你应该总是在连接的两端都关闭套接字。对于服务器来说,应该在read调用返回0时关闭套接字,但如果套接字是一个面向连接类型的,并且设置了SOCK_LINGER选项,close调用会在改套接字还有未传输数据时阻塞。(这里就涉及到如何设置套接字选项,这里不细讲)

 文章来源地址https://www.toymoban.com/news/detail-797938.html

 

到了这里,关于彻底弄懂套接字的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【网络】网络编程套接字(一)

    在前面我们说过可以使用IP地址来标识一台主机,但是我们光有IP地址就可以完成通信了嘛? 答案是:不可以,当我们的主机接收到了数据以后还要确定这个数据是发送给哪一个进程的,两台主机的两个软件进行网络通信时,我们还需要有一个其他的标识来区分出这个数据要给

    2024年02月06日
    浏览(54)
  • 【JavaEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月20日
    浏览(69)
  • 【JaveEE】网络编程之TCP套接字、UDP套接字

    目录 1.网络编程的基本概念 1.1为什么需要网络编程  1.2服务端与用户端 1.3网络编程五元组  1.4套接字的概念 2.UDP套接字编程 2.1UDP套接字的特点  2.2UDP套接字API 2.2.1DatagramSocket类 2.2.2DatagramPacket类  2.2.3基于UDP的回显程序 2.2.4基于UDP的单词查询  3.TCP套接字编程 3.1TCP套接字的特

    2023年04月13日
    浏览(141)
  • 【Linux网络编程】网络编程套接字二

    喜欢的点赞,收藏,关注一下把! TCP和UDP在编程接口上是非常像的,前面我们说过TCP是面向连接的,UDP我们上篇博客也写过了,我们发现UDP服务端客户端写好启动直接就发消息了没有建立连接。TCP是建立连接的,注定在写的时候肯定有写不一样的地方。具体怎么不一样,我们

    2024年04月15日
    浏览(61)
  • 网络编程套接字(3)——Java数据报套接字(UDP协议)

    目录 一、Java数据报套接字通信模型 二、UDP数据报套接字编程 1、DatagramSocket         (1)DatagramSocket构造方法         (2)DatagramSocket方法 2、DatagramPacket         (1)DatagramPacket构造方法         (2)DatagramPacket方法 3、InetSocketAddress 三、代码示例:回显服务

    2024年03月12日
    浏览(91)
  • 网络编程【TCP流套接字编程】

    目录 TCP流套接字编程 1.ServerSocket API 2.Socket API 3.TCP中的长短连接 4.回显程序(短连接) 5.服务器和客户端它们的交互过程 6.运行结果及修改代码   ❗❗两个核心: ServerSocket     Socket 1.ServerSocket API ✨ ServerSocket 是创建 TCP服务端Socket的API ServerSocket 构造方法: ServerSocket 方法 :

    2023年04月12日
    浏览(128)
  • UDP网络套接字编程

    先来说说数据在网络上的传输过程吧,我们知道系统其实终究是根据冯诺依曼来构成的,而网络数据是怎么发的呢? 其实很简单,网络有五层。如下: 如上图,我们知道的是,每层对应的操作系统中的那些地方,有些可能说是网络有七层,其实和这个五层一样的。下面我们

    2024年02月04日
    浏览(45)
  • 【网络编程】网络编程套接字(三)TCP网络程序

    与前边的UDP网络程序相同,创建套接字的接口都是socket,下边对socket接口进行介绍: 协议家族选择AF_INET,因为我们要进行网络通信。 而第二个参数,为服务类型,传入SOCK_STREAM,我们编写TCP程序,所以要选择流式的服务。 第三个参数默认传入0,由前两个参数就可以推出这是

    2024年02月16日
    浏览(57)
  • 【网络编程】网络编程 和 Socket 套接字认识

    ✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是网络。 相比本地资源来说,网络提供了更为丰富的网络资源:

    2023年04月15日
    浏览(117)
  • 6.网络编程套接字(上)

    大家好,我是晓星航。今天为大家带来的是 网络编程套接字 相关的讲解!😀 用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。 与本地打开视频文件类似,只是视频文件这个资源的来源是网络。 相比本地资源来说,网络

    2024年02月10日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包