字节跳动青训营 | SOCKET属性与操作

140 阅读6分钟

SOCKET(套接字)是计算机网络中的一个重要概念,它充当了网络通信的桥梁。以下是对SOCKET的详细解释:

一、SOCKET的定义与功能

  1. 定义
    SOCKET是一个抽象层,它允许应用程序通过网络进行通信。它是计算机之间进行通信的一种约定或方式,为网络通信提供了一个标准的接口。
  2. 功能
    SOCKET用于跨网络的不同主机上的应用程序之间的数据交换。它使得应用程序可以像操作文件一样对网络进行读写操作,包括建立连接、发送数据、接收数据以及关闭连接等。

二、SOCKET的工作原理

  1. 通信流程

    • 服务器端

      • 创建一个服务器套接字,并指定一个端口号。
      • 绑定服务器套接字到指定的端口。
      • 服务器套接字进入监听状态,等待客户端的连接请求。
      • 当客户端尝试连接时,服务器套接字接受连接请求,并创建一个新的套接字用于与客户端通信。
      • 通过新创建的套接字与客户端进行数据交换。
      • 通信完成后,关闭与客户端的连接,并继续监听新的连接请求。
    • 客户端

      • 创建一个客户端套接字。
      • 指定服务器的IP地址和端口号,以便连接到正确的服务器。
      • 通过客户端套接字向服务器发送连接请求。
      • 连接成功后,通过套接字与服务器进行数据交换。
      • 通信完成后,关闭与服务器的连接。
  2. 数据传输
    SOCKET数据传输是基于TCP/IP协议栈的。TCP协议提供了可靠的、面向连接的通信服务,而UDP协议则提供了不可靠的、无连接的通信服务。在实际应用中,可以根据需求选择合适的协议。

三、SOCKET的编程接口

不同的操作系统和编程语言可以通过不同的方式来实现SOCKET编程接口。这些接口通常以一组函数的形式出现,包括创建套接字、绑定套接字、监听连接、接受连接、发送数据、接收数据以及关闭套接字等。例如,在Java中,可以使用java.net包提供的SocketServerSocket类来进行SOCKET编程。

四、SOCKET的应用场景

SOCKET广泛应用于网络通信中,实现数据的发送和接收。以下是一些常见的应用场景:

  • 即时通讯:如QQ、微信等即时通讯软件,使用SOCKET进行客户端之间或客户端与服务器之间的即时消息传输。
  • 网络游戏:多人在线游戏中,客户端通过SOCKET连接到游戏服务器,以实现实时的游戏状态同步和玩家互动。
  • 远程控制:远程桌面应用、远程维护工具等,通过SOCKET连接实现对远程计算机的控制。
  • 文件传输:如FTP(文件传输协议)客户端通过SOCKET连接到FTP服务器,实现文件的上传和下载。
  • 网络服务消费:很多基于网络的服务,如Web服务、数据库服务等,客户端通过SOCKET连接到服务提供者进行数据查询、提交等操作。
  • 物联网(IoT) :物联网设备通过SOCKET连接到云服务器或其他设备,实现数据交换和远程控制。
  • 流媒体播放:如视频会议、在线直播等应用,客户端通过SOCKET连接到媒体服务器实现音视频数据的实时传输和播放。

五、SOCKET的优缺点

  • 优点

    • 传输数据为字节级,传输数据可自定义且数据量小(对于手机应用来说费用低)。
    • 传输数据时间短,性能高。
    • 适合于客户端和服务器端之间信息的实时交互。
    • 可以加密,数据安全性强。
  • 缺点

    • 需要对传输的数据进行解析并转化成应用级的数据。
    • 对开发人员的开发水平要求高。
    • 相对于HTTP协议传输来说,增加了开发量。

综上所述,SOCKET是计算机网络通信中的重要组成部分。它提供了标准的网络通信接口和灵活的数据传输方式,使得应用程序可以方便地进行网络通信和数据交换。

以上简介与原理来源于网络,仅供没有基础的同学参考与学习。下面介绍主要操作。

非阻塞模式设置

一般来说,在网络中,服务端与客户端进行通讯时会发生阻塞,这会大大影响程序的性能与运行稳定性。 在C++中,我们可以通过设置sock_fdflag为非阻塞,这样在使用该sock_fd发送消息与接收消息时程序会使用非阻塞的方式运行。

int flag = fcntl(sock_fd, F_GETFL, 0);
flag |= O_NONBLOCK;
fcntl(sock_fd, F_SETFL, flag);

缓冲区大小设置

socket无法直接将数据发送到网卡,只能先将数据发送到操作系统数据发送缓冲区。然后网卡从数据发送缓冲区中获取数据,再发送到接收方。这时候就会出现数据读写速度不匹配问题,如果用户程序发送数据的速度比网卡读取的速度快,那么发送缓冲区将会很快被写满,这时候使用send发送数据会被阻塞(写入发生阻塞)。 这里依旧以C++为例,可以手动设置缓冲区大小。

int buff_size = xx; // the buffer size you want to set.
setsockopt(sock_fd, SOL_SOCKET, SO_SNDBUF, &buff_size, sizeof(buff_size));

接收缓冲区同理。

int buff_size = xx; // the buffer size you want to set.
setsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &buff_size, sizeof(buff_size));

需要注意的是,发送缓冲区和接收缓冲区这两个区域是每个socket连接都有的,在socket创建完成时,这两块内存就已经被开辟出来了。

Linger

Linger 是函数close关闭TCP连接时的行为。缺省的close行为是,如果有数据残留在socket发送缓冲区中则系统将继续发送这些数据给对方,等待被确认后返回。

struct linger l;
memset(&l, 0, sizeof(l));
l.l_onoff = activate; // on or off
l.l_linger = seconds; // time (s)
setsockopt(sock_fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l));

Keep Alive

无论是服务端还是客户端,一方开启KeepAlive功能后,就会自动在规定时间内向对方发送心跳包,而另一方在收到心跳包后就会自动回复,以告诉对方我仍然在线。

int flag = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_KEEPALIVE, &flag, sizeof(flag));

REUSEADDR

允许服务器绑定一个地址,即使这个地址当前已经存在已建立的连接。

int flag = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag));

参考链接

TCP/IP网络编程从零开始