Socket的通信原理和使用

article/2025/10/7 18:08:09

 目录

一、什么是 Socket?

二、Socket 通信过程

        2.1 通信过程介绍

       2.2 实现TCP建立连接的三次握手过程

 三、 使用Socket进行通信【php】

        3.1 PHP中Socket常量和函数介绍

        3.2 php实现Socket通信过程 


一、什么是 Socket?

Socket 的中文翻译过来就是“套接字”。套接字是什么,我们先来看看它的英文含义:插座。

socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用“打开open –> 读写write/read –> 关闭close”模式来操作。我的理解就是Socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭),这些函数我们在后面进行介绍。

Socket通信主要是基于两种协议实现的:

(1)TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。

(2)UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。

通过下图说明实现通信过程之间关系:

 

二、Socket 通信过程

2.1 通信过程介绍

Socket 保证了不同计算机之间的通信,也就是网络通信。对于网站,通信模型是服务器与客户端之间的通信。两端都建立了一个 Socket 对象,然后通过 Socket 对象对数据进行传输。通常服务器处于一个无限循环,等待客户端的连接:

 

根据socket通信基本流程图,总结通信的基本步骤:
服务器端:
第一步:创建一个用于监听连接的Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Bind()方法绑定EndPoint;
第四步:用socket对像的Listen()方法开始监听;
第五步:接收到客户端的连接,用socket对像的Accept()方法创建一个新的用于和客户端进行通信的socket对像;
第六步:通信结束后一定记得关闭socket;
客户端:
第一步:建立一个Socket对像;
第二步:用指定的端口号和服务器的ip建立一个EndPoint对像;
第三步:用socket对像的Connect()方法以上面建立的EndPoint对像做为参数,向服务器发出连接请求;
第四步:如果连接成功,就用socket对像的Send()方法向服务器发送信息;
第五步:用socket对像的Receive()方法接受服务器发来的信息 ;
第六步:通信结束后一定记得关闭socket; 

2.2 实现TCP建立连接的三次握手过程

三次握手是 TCP 连接的建立过程。在握手之前,主动打开连接的客户端结束 CLOSE 阶段,被动打开的服务器也结束 CLOSE 阶段,并进入 LISTEN 阶段。随后进入三次握手阶段:

① 首先客户端向服务器发送一个 SYN 包,并等待服务器确认,其中:

  • 标志位为 SYN,表示请求建立连接;
  • 序号为 Seq = x(x 一般取随机数);
  • 随后客户端进入 SYN-SENT 阶段。

② 服务器接收到客户端发来的 SYN 包后,对该包进行确认后结束 LISTEN 阶段,并返回一段 TCP 报文,其中:

  • 标志位为 SYN 和 ACK,表示确认客户端的报文 Seq 序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接;
  • 序号为 Seq = y;
  • 确认号为 Ack = x + 1,表示收到客户端的序号 Seq 并将其值加 1 作为自己确认号 Ack 的值,随后服务器端进入 SYN-RECV 阶段。

③ 客户端接收到发送的 SYN + ACK 包后,明确了从客户端到服务器的数据传输是正常的,从而结束 SYN-SENT 阶段。并返回最后一段报文。其中:

  • 标志位为 ACK,表示确认收到服务器端同意连接的信号;
  • 序号为 Seq = x + 1,表示收到服务器端的确认号 Ack,并将其值作为自己的序号值;
  • 确认号为 Ack= y + 1,表示收到服务器端序号 seq,并将其值加 1 作为自己的确认号 Ack 的值。
  • 随后客户端进入 ESTABLISHED。

当服务器端收到来自客户端确认收到服务器数据的报文后,得知从服务器到客户端的数据传输是正常的,从而结束 SYN-RECV 阶段,进入 ESTABLISHED 阶段,从而完成三次握手。

三、 使用Socket进行通信【php】

3.1 PHP中Socket的常量和函数介绍

常量:

SOL_TCP/SOL_UDP   使用TCP/UDP连接模式

AF_INET   这是大多数用来产生socket的协议,使用TCP或UDP来传输,用在IPv4的地址
AF_INET6   与上面类似,不过是来用在IPv6的地址
AF_UNIX 本地协议,使用在Unix和Linux系统上,它很少使用,一般都是当客户端和服务器在同一台机器上的时候使用
SOCK_STREAM 这个协议是按照顺序的、可靠的、数据完整的基于字节流的连接。这是一个使用最多的socket类型,这个socket是使用TCP来进行传输。
SOCK_DGRAM 这个协议是无连接的、固定长度的传输调用。该协议是不可靠的,使用UDP来进行它的连接。
SOCK_SEQPACKET 这个协议是双线路的、可靠的连接,发送固定长度的数据包进行传输。必须把这个包完整的接受才能进行读取。
SOCK_RAW 这个socket类型提供单一的网络访问,这个socket类型使用ICMP公共协议。(ping、traceroute使用该协议)
SOCK_RDM 这个类型是很少使用的,在大部分的操作系统上没有实现,它是提供给数据链路层使用,不保证数据包顺序

函数:
socket_create(int $domain,int $type,int $protocol)    创建一个Socket连接
socket_bind(resource $socket,string $address [,int $port = 0] )    把socket绑定在一个IP地址和端口上
socket_clear_error ([ resource $socket ] )   清除socket的错误或者最后的错误代码
socket_close(resource $socket)     关闭一个socket资源
socket_connect(resource $socket,string $address [,int $port = 0] )   开启一个socket连接,此函数尝试连接服务端
socket_create_listen ( int $port [, int $backlog = 128 ] )   在指定端口打开一个socket监听
socket_create_pair ( int $domain , int $type , int $protocol , array &$fd )   产生一对没有区别的socket到一个数组里
socket_get_option ( resource $socket , int $level , int $optname )   获取socket选项
socket_getpeername(resource $socket, string& $address [,int &$port] )  获取远程类似主机的ip地址
socket_getsockname ( resource $socket , string &$addr [, int &$port ] )   获取本地socket的ip地址
socket_iovec_add()    添加一个新的向量到一个分散/聚合的数组
socket_iovec_alloc()   这个函数创建一个能够发送接收读写的iovec数据结构
socket_iovec_delete()   删除一个已经分配的iovec
socket_iovec_fetch()   返回指定的iovec资源的数据
socket_iovec_free()    释放一个iovec资源
socket_iovec_set()    设置iovec的数据新值
socket_last_error ([ resource $socket ] )   获取当前socket的最后错误代码
socket_listen(resource $socket[,int $backlog = 0] )     监听由指定socket的所有连接
socket_read(resource $socket, int $length [,int $type = PHP_BINARY_READ] )    读取指定长度的数据
socket_readv()     读取从分散/聚合数组过来的数据
socket_recv(resource $socket, string &$buf,int $len, int $flags)     从socket里接收数据到缓存
socket_recvfrom()    接受数据从指定的socket,如果没有指定则默认当前socket
socket_recvmsg()    从iovec里接受消息
 socket_select(array &$read,array &$write,array &$except,int $tv_sec [,int $tv_usec = 0] )     多路选择
socket_send(resource $socket, string $buf, int $len, int $flags)     这个函数发送数据到已连接的socket
socket_sendmsg ( resource $socket , array $message [, int $flags = 0 ] )     发送消息到socket
socket_sendto ( resource $socket , string $buf , int $len , int $flags , string $addr [, int $port = 0 ] )    发送消息到指定地址的socket
socket_set_block ( resource $socket )   在socket里设置为块模式
socket_set_nonblock ( resource $socket )   socket里设置为非块模式
socket_set_option ( resource $socket , int $level , int $optname , mixed $optval )    设置socket选项
socket_shutdown ( resource $socket [, int $how = 2 ] )    这个函数允许你关闭读、写、或者指定的socket
socket_strerror ( int $error_number)   返回指定错误号的详细错误
socket_write(resource $socket, string $buffer [,int $length= 0] )     写数据到socket缓存
socket_writev()    写数据到分散/聚合数组

socket_set_option ( resource $socket , int $level , int $optname , mixed $optval ) 设置套接字的套接字选项,通过optname参数设置指定的选项 在指定的协议级别level,设置为套接字的optval参数指向的值

optname 参数列表:

OptionDescriptionType
SO_DEBUG报告是否正在记录调试信息.int
SO_BROADCAST报告是否支持广播消息的传输.int
SO_REUSEADDR报告本地地址是否可以重复使用.int
SO_REUSEPORT报告本地端口是否可以重用.int
SO_KEEPALIVE报告是否通过定期传输消息使连接保持活动状态。 如果连接的套接字无法响应这些消息,则连接断开,并且使用SIGPIPE信号通知写入该套接字的进程.int
SO_LINGER如果存在数据,则报告套接字是否在socket_close()上停留。 默认情况下,当套接字关闭时,它将尝试发送所有未发送的数据。 对于面向连接的套接字,socket_close()将等待其对等方确认数据.
如果l_OnOff非零且l_linger为零,则在面向连接的套接字的情况下,将丢弃所有未发送的数据,并将RST(重置)发送到对等方
另一方面,如果l_onoff不为零且l_linger不为零,则socket_close()将阻塞,直到所有数据发送完毕或l_linger中指定的时间过去。 如果套接字是非阻塞的,则socket_close()将失败并返回错误
array . 该数组将包含两个键:l_onoff和l_linger
SO_OOBINLINE报告“套接字”是否内联带外数据.int
SO_SNDBUF报告发送缓冲区的大小。.int
SO_RCVBUF报告接收缓冲区的大小.int
SO_ERROR报告有关错误状态的信息并清除它int
SO_TYPE报告套接字类型(e.g.SOCK_STREAM).int
SO_DONTROUTE报告传出邮件是否绕过标准路由功能int
SO_RCVLOWAT报告套接字输入操作要处理的最小字节数.int
SO_RCVTIMEORep报告输入操作的超时值.array . 该数组将包含两个键:sec是超时值的秒部分,而usec是超时值的微秒部分.
SO_SNDTIMEO报告超时值,该超时值指定由于流控制阻止发送数据而导致输出功能阻塞的时间.array . 该数组将包含两个键:sec是超时值的秒部分,而usec是超时值的微秒部分.
SO_SNDLOWAT报告套接字输出操作要处理的最小字节数.int
TCP_NODELAY报告是否禁用Nagle TCP算法.int
MCAST_JOIN_GROUP加入多播组 (added in PHP 5.4)array 使用键“group” ,指定一个字符串
MCAST_LEAVE_GROUP离开多播组 (added in PHP 5.4)array
MCAST_BLOCK_SOURCE阻止从特定源到达特定多播组的数据包,这些数据包必须事先已加入. (added in PHP 5.4)array 具有与MCAST_JOIN_GROUP相同​​的键,以及一个映射到字符串的额外键source
MCAST_UNBLOCK_SOURCE取消阻止(再次开始接收)从特定源地址到达特定多播组的数据包,这些数据包必须事先已加入. (added in PHP 5.4)array
MCAST_JOIN_SOURCE_GROUP接收发往特定组播组的数据包,该组播组的源地址与特定值匹配. (added in PHP 5.4)array
MCAST_LEAVE_SOURCE_GROUP停止接收发往源地址与特定值匹配的特定组播组的数据包. (added in PHP 5.4)array
IP_MULTICAST_IFIPv4组播数据包的传出接口. (added in PHP 5.4)指定接口号的int或字符串返回接口索引。 请注意,与C API不同,此选项不使用IP地址.请注意,与C API不同,此选项不使用IP地址。 这样可以消除IP_MULTICAST_IFIPV6_MULTICAST_IF之间的接口差异.
IPV6_MULTICAST_IFIPv6组播数据包的出接口. (added in PHP 5.4)IP_MULTICAST_IF相同.
IP_MULTICAST_LOOPIPv4数据包的多播回送策略,该策略确定此套接字发送的多播数据包是否也到达该主机使用的出接口上已加入同一多播组的同一主机中的接收者。默认情况下就是这种情况. (added in PHP 5.4)int 任何值都将被接受,并将按照通常的PHP规则转换为布尔值
IPV6_MULTICAST_LOOPIP_MULTICAST_LOOP类似,但适用于IPv6 (added in PHP 5.4)int . 参阅IP_MULTICAST_LOOP.
IP_MULTICAST_TTLIPv4组播数据包的生存时间。 该值应介于0(不要离开接口)和255之间。默认值是1(仅到达本地网络). (added in PHP 5.4)int 取值范围0 ~255.
IPV6_MULTICAST_HOPSIP_MULTICAST_TTL类似,但用于IPv6数据包。 值-1也被接受,这意味着应该使用默认路由. (added in PHP 5.4)int betw

3.2 php实现Socket通信过程 

创建服务端代码 socket_server.php

<?php//服务端//创建服务端的socket套接流,net协议为IPv4,protocol协议为TCP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//绑定接收的套接流主机和端口
$ip = '127.0.0.1';
$port = '8888';
socket_bind($socket, $ip, $port);
//监听套接流
socket_listen($socket);while(true) {//接收客户端传过来的信息$connection = socket_accept($socket);if($connection){echo $connection.": connection success\n";//向socket_accept的套接流写入信息socket_write($connection, "connection success\n");}//读取客户端传过来的资源,并转化为字符串while($message = socket_read($connection, 1024, PHP_NORMAL_READ)){if(trim($message)){echo $connection.": ".$message."\n";}}//关闭客户端连接socket_close($connection);
}//关闭建立的socket套接流
socket_close($socket);

创建客户端代码 socket_client.php

<?php//客户端//创建服务端的socket套接流,net协议为IPv4,protocol协议为TCP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//发送套接流的最大超时时间为3秒
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 3, "usec" => 0));//绑定接收的套接流主机和端口
$ip = '127.0.0.1';
$port = '8888';
$connection = socket_connect($socket, $ip, $port);//接收服务端传过来的信息
if($data = socket_read($socket, 1024, PHP_NORMAL_READ)){echo 'server: '.$data;
}while(true){//向socket_accept的套接流写入信息$data = fread(STDIN, 1024);if($data){socket_write($socket, $data."\n");}}//关闭建立的socket套接流
socket_close($socket);

执行结果:


http://chatgpt.dhexx.cn/article/2u3EHTSJ.shtml

相关文章

linux 网络编程socket

前言 socket&#xff08;套接字&#xff09;是linux下进程间通信的一种方式&#xff0c;通常使用C-S&#xff08;客户端-服务端&#xff09;的方式通信&#xff0c;它可以是同一主机下的不同进程间通信或者不同主机的进程通信。 socket是夹在应用层和TCP/UDP协议层间的软件抽象…

什么是socket?socket详解

“一切皆Socket&#xff01;” 话虽些许夸张&#xff0c;但是事实也是&#xff0c;现在的网络编程几乎都是用的socket。 ——有感于实际编程和开源项目研究。 我们深谙信息交流的价值&#xff0c;那网络中进程之间如何通信&#xff0c;如我们每天打开浏览器浏览网页时&#xff…

【Python】Socket的简单应用

前言 今天“出差在外”&#xff0c;晚上又琐事缠身&#xff0c;实在也没办法特别沉下心去学什么内容&#xff0c;但还是不希望一天一篇的flag就此倒下&#xff0c;只能多多参考别人的博客浅浅学习一下python的socket应用&#xff0c;后续课内做实验了&#xff0c;学习更深入的…

http和socket关系

一、先说下HTTP网络协议栈 二、连接过程 三、重点来了&#xff0c;TCP套接字编程&#xff0c;也就是所谓的socket 四、通过比较发现http和socket完全是两个不同的概念&#xff0c;http是应用层的&#xff0c;socket是传输层和网络层的&#xff0c;http要基于socket实现。httpcl…

SOCKET函数详解

socket原理 1.socket socket位于应用层和TCP/IP协议通信中间&#xff0c;抽象成一组接口 1.服务端首先初始化Socket(),然后和接口进行绑定bind()和监听listen(),然后调用accept()进行阻塞。 2.客户端初始化socket(),然后调用connect&#xff08;&#xff09;与服务端进行连接…

用大白话解释什么是Socket

好好学习&#xff0c;天天向上 本文已收录至我的Github仓库DayDayUP&#xff1a;github.com/RobodLee/DayDayUP&#xff0c;欢迎Star&#xff0c;更多文章请前往&#xff1a;目录导航 前言 我在去年就学习过Java中Socket的使用&#xff0c;但对于Socket的理解一直都是迷迷糊糊…

Socket详解

“一切皆Socket&#xff01;” 话虽些许夸张&#xff0c;但是事实也是&#xff0c;现在的网络编程几乎都是用的socket。 ——有感于实际编程和开源项目研究。 我们深谙信息交流的价值&#xff0c;那网络中进程之间如何通信&#xff0c;如我们每天打开浏览器浏览网页时&#xff…

Java socket详解

整理和总结了一下经常遇到的问题&#xff1a; 1. 客户端socket发送消息后&#xff0c;为什么服务端socket没有收到&#xff1f; 2. 使用while 循环实现连续输入&#xff0c;是不是就是多线程模式&#xff1f; 3. 对多线程处理机制不是很明白&#xff0c;希望详细讲解…

Socket的详细介绍

文章目录 前言1-Socket出现的原因1.1-Socket出现的背景1.2-Socket解决的问题 2-Socket的组成及关键点2.1-What&#xff1a;什么是Socket&#xff1f;2.2-How&#xff1a; Socket通信实现的步骤2.3-How&#xff1a; Socket编写流程 3-Socket的关键实现3.1-socket()函数创建套接字…

Socket到底是什么?

学习java网络编程一段时间后&#xff0c;突然被问到socket是什么&#xff1f;回答不上来&#xff0c;感觉很尴尬&#xff0c;于是赶紧是查阅资料。 网络由下往上分为 物理层 、数据链路层 、 网络层 、 传输层 、 会话层 、 表现层 和 应用层。 通过初步了解&#xff0c;我知道…

什么是Socket?

一、什么是Socket&#xff1f; 在计算机通信领域&#xff0c;socket 被翻译为“套接字”&#xff08;套接字主机端口号&#xff09;&#xff0c;它是计算机之间进行通信的一种约定或一种方式。通过 socket这种约定&#xff0c;一台计算机可以接收其他计算机的数据&#xff0c;也…

Socket的学习(一)什么是Socket?

本文参考的是《Socket通信原理》https://www.cnblogs.com/wangcq/p/3520400.html 一、TCP/IP UDP是什么&#xff1f; TCP/IP&#xff08;Transmission Control Protocol/Internet Protocol&#xff09;即传输控制协议/网间协议&#xff0c;是一个工业标准的协议集&#xff0c…

整数划分(递归方法)

最近讲到了递归&#xff0c;老师布置了一道经典的整数划分问题&#xff0c;浏览了网上很多代码&#xff0c;还是似懂非懂&#xff0c;想找张清晰地展现递归过程的图片也没有&#xff0c;今天想了想&#xff0c;自己画了一张才发现&#xff0c;想完整清晰地表现这个过程确实真的…

递归算法--整数划分

何为整数划分&#xff1a; 所谓整数划分&#xff0c;是指把一个正整数n写成为 其中&#xff0c; 为正整数&#xff0c;并且 &#xff1b; 为n的一个划分。 如果 中的最大值不超过m&#xff0c;即 &#xff0c;则称它属于n的一个m划分。 例如&#xff1a;6的划分&#xff1a; 6…

递归实现整数划分

递归思想 递归是算法设计中的一种基本而重要的算法。递归方法通过函数调用自身将问题转化为本质相同但规模较小的子问题&#xff0c;是分治策略的具体体现。 不多废话&#xff0c;直接上故事 ->从前有座山&#xff0c;山上有座庙&#xff0c;庙里有个老和尚在给小和尚讲故…

复杂的整数划分

复杂的整数划分 又到了动态规划的时间了&#xff01; 记得我之前讲过的三要素哦 下面这一条题目其实思路并不是非常的难&#xff0c;但是在细节处理上要非常仔细&#xff0c;而且它有3个相互独立的动态规划问题。 总时间限制: 200ms 内存限制: 65536kB 描述 将正整数n 表…

整数划分(DP)

一个正整数 n 可以表示成若干个正整数之和&#xff0c;形如&#xff1a;nn1n2…nk&#xff0c;其中 n1≥n2≥…≥nk,k≥1。 我们将这样的一种表示称为正整数 n 的一种划分。 现在给定一个正整数 n&#xff0c;请你求出 n 共有多少种不同的划分方法。 输入格式 共一行&#x…

【算法】整数划分问题

描述 整数划分问题是算法中的一个经典命题之一。把一个正整数n表示成一系列正整数之和&#xff1a; 正整数n的这种表示称为正整数n的划分。正整数n的不同划分个数称为正整数n的划分数&#xff0c;记作P(n) 。 正整数6有如下11种不同的划分&#xff0c;所以P(6)11。 6 51 42, …

【递归】整数划分(C++)

一、什么是整数划分 所谓整数划分&#xff0c;是指把一个正整数n写成如下形式&#xff1a; n m 1 m 2 ⋅ ⋅ ⋅ m i nm_1m_2m_i nm1​m2​⋅⋅⋅mi​&#xff1b; 其中 m i m_i mi​为正整数&#xff0c;并且 1 ≤ m i ≤ n 1 \leq m_i \leq n 1≤mi​≤n&#xff0c;则 { …

整数划分问题的递归解决(详解)

整数划分问题 这个问题在网上其实有好多博客、文章&#xff0c;本人认为讲的都稍有粗略&#xff0c;这篇文章是个人写的认为稍微详细一点的&#xff01;&#xff01; 将正整数n表示为一系列正整数之和&#xff0c; nn1n2n3n4......nk &#xff08;其中&#xff0c;n1>n2&…