socket套接字详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/daaikuaichuan/article/details/83061726

  套接字是一种通信机制(通信的两方的一种约定),凭借这种机制,不同主机之间的进程可以进行通信。我们可以用套接字中的相关函数来完成通信过程

  套接字的特性有三个属性确定,它们是:域(domain),类型(type),和协议(protocol)。

#include<sys/types.h>
#include<sys/socket.h>
int socket(int domain, int type, int protocol);

一、域(domain)

  域指定套接字通信中使用的网络介质。最常见的套接字域是 AF_INET(IPv4)或者AF_INET6(IPV6),它是指 Internet 网络,许多 Linux 局域网使用的都是该网络,当然,因特网自身用的也是它。


二、类型(type)

  • 流套接字(SOCK_STREAM):

  流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP(The Transmission Control Protocol)协议。

  • 数据报套接字(SOCK_DGRAM):

  数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。由于数据报套接字不能保证数据传输的可靠性,对于有可能出现的数据丢失情况,需要在程序中做相应的处理。

  • 原始套接字(SOCK_RAW):

  原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字


三、协议(protocol)

  • 0:

   使用默认协议;

  • IPPROTO_TCP;

   使用TCP协议;

  • IPPROTO_UDP;

   使用UDP协议;


四、socket缓冲区以及阻塞模式

1、缓冲区简介

  每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。

  write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。
  read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取。
在这里插入图片描述

  • I/O缓冲区在每个TCP套接字中单独存在;
  • I/O缓冲区在创建套接字时自动生成;
  • 即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
  • 关闭套接字将丢失输入缓冲区中的数据。

2、阻塞模式

【对于TCP套接字(默认情况下),当使用 write()/send() 发送数据时】:

1. 首先会检查缓冲区,如果缓冲区的可用空间长度小于要发送的数据,那么 write()/send() 会被阻塞(暂停执行),直到缓冲区中的数据被发送到目标机器,腾出足够的空间,才唤醒 write()/send() 函数继续写入数据;

2. 如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write()/send() 也会被阻塞,直到数据发送完毕缓冲区解锁,write()/send() 才会被唤醒。如果TCP协议正在向网络发送数据,那么输出缓冲区会被锁定,不允许写入,write()/send() 也会被阻塞,直到数据发送完毕缓冲区解锁,write()/send() 才会被唤醒;

3. 如果要写入的数据大于缓冲区的最大长度,那么将分批写入。如果要写入的数据大于缓冲区的最大长度,那么将分批写入;

4. 直到所有数据被写入缓冲区 write()/send() 才能返回。直到所有数据被写入缓冲区 write()/send() 才能返回。

【当使用 read()/recv() 读取数据时】:

1. 首先会检查缓冲区,如果缓冲区中有数据,那么就读取,否则函数会被阻塞,直到网络上有数据到来

2. 如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()/recv() 函数再次读取。如果要读取的数据长度小于缓冲区中的数据长度,那么就不能一次性将缓冲区中的所有数据读出,剩余数据将不断积压,直到有 read()/recv() 函数再次读取;

3. 直到读取到数据后 read()/recv() 函数才会返回,否则就一直被阻塞。

参考:https://www.cnblogs.com/kex1n/p/6501977.html
https://blog.csdn.net/lianghe_work/article/details/45170359

猜你喜欢

转载自blog.csdn.net/daaikuaichuan/article/details/83061726