socket
socket
socket是网络上运行的两个程序间双向通讯的一端,既可以接收请求也可以发送请求,利用它可以方便的编写网络上数据传递。
socket连接过程:
1.服务器监听
服务器socket并不定位具体的客户端socket,而是处于等待链接的状态,实时监控网络状态。
2.客户端请求
客户端socket发出连接请求,要连接的目标是服务端socket,为此,客户端socket必须先描述它要连接的服务端socket,指出服务端socket的地址和端口号,然后想服务端socket提出连接请求。
3.连接确认
当服务端socket监听到或者说是接收到客户端socket的连接请求,它就响应客户端socket的请求,建立一个新的线程,把服务端socket的描述发给客户端,一旦客户端确认了,连接就好了。服务端socket基础处于监听状态。
TCP/IP、HTTP、Socket的区别
这三个概念是比较容易混淆的概念,这里尽量解释一下三者之间的区别。
随着计算机网络体系结构的发展,OSI七层网络模型诞生了,这个模型把开放系统的通信功能划分为七个层次,一次完整的通信如下图:
每一层都是相互独立的,它利用其下一层提供的服务并为其上一层提供服务,而与其它层的具体实现无关,所谓"服务"就是下一层向上一层提供的通信功能和层之间的会话约定,一般用通信原语实现。上图中,从下至上分别给层编号为1~7,其中1~4层为下层协议,5~7层为上层协议,接着回到我们的概念:
1、TCP/IP讲的其实是两个东西:TCP和IP。IP是一种网络层的协议,用于路由选择、网络互连
2、TCP是一种传输层协议,用于建立、维护和拆除传送连接,在系统之间提供可靠的透明的数据传送
3、HTTP是一种应用层协议,提供OSI用户服务,例如事物处理程序、文件传送协议和网络管理等,其目的最终是为了实现应用进程之间的信息交换
至于Socket,它只是TCP/IP网络的API而已,Socket接口定义了许多函数,用以开发TCP/IP网络上的应用程序,组织数据,以符合指定的协议。
ISO-OSI七层协议经典架构:物理层、数据链路层、网络层、传输层、会话层、表示层和应用层 (物数,网传,会表应)
socket两种模式
socket有两种操作方式:面向连接和无连接的。面向连接的socket操作就像一部电话,必须建立一个连接和一个呼叫,所有事情在到达是的顺序和它们出发的顺序一样,无连接的socket就想一个邮件投递,没有什么保证,顺序很可能会不同。
具体使用什么模式得看场景,如果可靠性更重要的话,用面向连接的好一些。
无连接的操作使用数据报协议(udp),这种模式下的socket不需要连接一个目的socket,只是简单的透出数据报,无连接的操作是高效的,但是不安全。
面向连接的操作使用tcp协议。效率低一些,但是安全性高。
Socket的两种模式
Socket有两种主要的操作方式:面向连接和无连接的。面向连接的Socket操作就像一部电话,必须建立一个连接和一人呼叫,所有事情在达到时的顺序与它们出发时的顺序一样,无连接的Socket操作就像是一个邮件投递,没有什么保证,多个邮件可能在达到时的顺序与出发时的顺序不一样。
到底使用哪种模式是由应用程序的需要决定的。如果可靠性更重要的话,用面向连接的操作会好一些,比如文件服务器需要数据的正确性和有序性,如果一些数据丢失了,系统的有效性将会失去;比如一些服务器间歇性地发送一些数据块,如果数据丢失了的话,服务器并不想要再重新发送一次,因为当数据到达的时候,它可能已经过时了。确保数据的有序性和正确性需要额外的操作的内存消耗,额外的消耗将会降低系统的回应速率。
无连接的操作使用数据报协议。一个数据报是一个独立的单元,它包含了所有这次投递的信息,就像一个信封,它有目的地址和要发送的内容,这个模式下的Socket并不需要连接一个目的Socket,它只是简单地透出数据报,无连接的操作是快速、高效的,但是数据安全性不佳。
面向连接的操作使用TCP协议。一个这个模式下的Socket必须在发送数据之前与目的地的Socket取得一个连接,一旦连接建立了,Socket就可以使用一个流接口:打开-->读-->写-->关闭,所有发送的信息都会在另一端以同样的顺序被接收。面向连接的操作比无连接的操作效率更低,但是数据的安全性更高。
服务器多监听
public class HandleThread extends Thread { private Socket socket; public HandleThread(Socket socket) { this.socket = socket; } public void run() { // Socket处理代码 } }
public static void main(String[] args) throws IOException { ServerSocket serverSocket = null; try { // 实例化一个服务器端的Socket连接 serverSocket = new ServerSocket(9999); } catch (IOException e) { System.err.print("Could not listen on port:9999"); System.exit(1); } Socket clientSocket = null; try { while (true) { // 用于接收来自客户端的连接 clientSocket = serverSocket.accept(); new HandleThread(clientSocket).start(); } } catch (IOException e) { System.err.println("Accept failed"); System.exit(1);a } }
由服务端多监听程序看IO模型
上面的代码,用一张图来表示一下这种IO模型:
即由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的一请求一应答通信模型,也就是Blocking IO模型即BIO。
该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增大后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,由于线程是Java虚拟机非常宝贵的系统资源,当线程数膨胀之后,系统的性能将极具下降,随着并发访问量的继续增大,系统将会发生线程堆栈溢出、创建新线程失败等问题,并最终导致进程宕机或者僵死,不能对外提供服务。
在高性能服务器应用领域,往往要面向成千上万个客户端的并发连接,这种模型显然无法满足高性能、高并发接入的场景。
当然具体问题具体分析,BIO性能虽然差,但是编程简单,如果客户端并发连接数不多,周边对接的网元不多,服务器的负载也不重,那么完全可以使用BIO进行作为服务器的IO模型。