linux Socket
基本的UDP Socket编程
UDP通信的流程比较简单,因此要搭建这么一个常用的UDP通信框架也是比较简单的。以下是UDP的框架图。
由以上框图可以看出,客户端要发起一次请求,仅仅需要两个步骤(socket和sendto),而服务器端也仅仅需要三个步骤即可接收到来自客户端的消息(socket、bind、recvfrom)。
Send, sendto, 和 sendmsg 用于向另一个套接字传递消息. Send 仅仅用于连接套接字,而 sendto 和 sendmsg 可用于任何情况下.
- read()/write()
- recv()/send()
- readv()/writev()
- recvmsg()/sendmsg()
- recvfrom()/sendto()
目标地址用 to 指定, tolen 定义其长度.消息的长度用 len 指定. 如果消息太长不能通过下层协议,函数将返回 EMSGSIZE 错误,消息也不会被送出.
在数据传送过程中所产生的错误不会返回给 send. 如果发生本地错误,则返回-1.
当要发送的消息长度大于套接字当前可用缓冲区时, send 将阻塞,除非在套接字上设置了非阻塞式输入输出模式. 对于非阻塞模式,这种情况下将返回 EAGAIN 错误.
udp的connect函数
UDP网络编程中也有connect函数,但它仅仅用于表示确定了另一方的地址,并没有其他含义。
有了以上认识后,我们可以知道UDP套接字有以下区分:
1)未连接的UDP套接字
2)已连接的UDP套接字
对于未连接的套接字,也就是我们常用的的UDP套接字,我们使用的是sendto/recvfrom进行信息的收发,目标主机的IP和端口是在调用sendto/recvfrom时确定的;
在一个未连接的UDP套接字上给两个数据报调用sendto函数内核将执行以下六个步骤:
1)连接套接字
2)输出第一个数据报
3)断开套接字连接
4)连接套接字
5)输出第二个数据报
6)断开套接字连接
对于已连接的UDP套接字,必须先经过connect来向目标服务器进行指定,然后调用read/write进行信息的收发,目标主机的IP和端口是在connect时确定的,也就是说,一旦connect成功,我们就只能对该主机进行收发信息了。
已连接的UDP套接字给两个数据报调用write函数内核将执行以下三个步骤:
1)连接套接字
2)输出第一个数据报
3)输出第二个数据报
由此可以知道,当应用进程知道给同一个目的地址的端口号发送多个数据报时,显示套接字效率更高。
下面给出带connect函数的UDP通信框架
Socket
端口通信运行在会话层,并不是应用层,Socket
抓包的原理与应用层Http(s)
有着显著的区别。准确的说,Http(s)
抓包是真正的“中间人”抓包,而Socket
抓包是在接口上进行转储;Http(s)
抓包是明显的将一套C/S
架构通信分裂成两套完整的通信过程,而Socket
抓包是在接口上将发送与接收的内容存储下来,并不干扰其原本的通信过程。
对于安卓应用来说,Socket
通信天生又分为两种Java
层Socket
通信和Native
层Socket
通信。
Java
层:使用的是java.net.InetAddress
、java.net.Socket
、java.net.ServerSocket
等类,与证书绑定的情形类似,也可能存在着自定义框架的Socket
通信,这时候就需要具体情况具体分析,比如谷歌的protobuf
框架等;Native
层:一般使用的是C Socket API
,一般hook
住send()
和recv()
函数可以得到其发送和接受的内容
Java层
Socket通信
Native层
Socket通信
一般使用的是C Socket API
,一般hook
住send()
和recv()
函数可以得到其发送和接受的内容。udp一般使用的sendto()