==
=
-
https://www.cnblogs.com/lcplcpjava/p/6581179.html
一、长连接和短连接的概念
1、长连接与短连接的概念:前者是整个通讯过程,客户端和服务端只用一个Socket对象,长期保持Socket的连接;后者是每次请求,都新建一个Socket,处理完一个请求就直接关闭掉Socket。所以,其实区分长短连接就是:整个客户和服务端的通讯过程是利用一个Socket还是多个Socket进行的。
可能你会想:这还不简单,长连接不就是不关Socket嘛,短连接不就是每次都关Socket每次都new Socket嘛。然而事实其实并没有那么简单的,请继续看下面的整理
2、关闭流而保持Socket正常?
在网上百度了一下,发现很多人都是以关闭流还是关闭Socket来区分长连接和短连接的,其实,个人感觉这种区分方法并没有什么意义:因为这里面有一个事实是,流关闭之后,便不能进行消息的发送(对应关闭输出流)或者接受(对应关闭输入流),因为其实关闭了对应的流,对应连接也就关闭了(这里所说的连接是发送消息的通道!),所以,流关闭而保持Socket开启,是没有达到长连接的效果,贴上测试代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
//发送核心方法 public String send(String send) throws IOException {
String rtn = null ;
BufferedWriter writer = null ;
OutputStreamWriter ow = null ;
OutputStream os = null ;
try {
os = socket.getOutputStream();
ow = new OutputStreamWriter(os);
writer = new BufferedWriter(ow);
char [] sendChar = send.toCharArray();
ArrayList<Integer> list = new ArrayList<Integer>();
for ( char ch:sendChar){
list.add(( int )ch);
}
//进行加密操作
list = encry(list);
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
writer.write(it.next());
}
writer.flush();
rtn = "发送成功!" ;
} finally {
//注意:直接关闭流将会导致socket关闭,只能通过shutdownOutput/input的方式关闭流
//另外,流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
// if(writer!=null){ // writer.close(); // } // if(ow!=null){ // ow.close(); // } // if(os!=null){ //os.close();
// } //socket.shutdownOutput();流关闭之后,相当于关闭底层的连接,除非新<br>new个socket,否则和客户端的连接相当于断开
}
return rtn;
}
|
这是我写的一个测试的发送消息的核心方法,在关闭了对应的流(无论是输出或者输入)之后,下一次调用getInputStream或者getOutputStream会抛出异常说:Socket is closed;这里讲明一个事实:Socket和流联系着,流关闭了,Socket其实也就相当于关闭状态!
其实这个也很好理解,Socket本来就是依靠流进行关闭的,流,就只有一个,你关闭了流,Socket赖以通讯的渠道也就关闭了,与客户的连接也断开了,所以抛出异常是很合理的。
所以,流关闭而要求Socket正常通讯是不可能的!
所以,如何实现长连接?
二、长连接的正确实现方式
1、不关闭流实现长连接?
前面讨论了,流关闭了而不关闭Socket,还是无法达到长连接的效果的,所以,要长连接,流必须不能关闭!那么,是不是直接不关闭流,然后每次要发消息就直接往流里面任进去数据,然后调用flush()方法强制刷新就行了?其实不行的,这样客户端是无法正常接收信息的,你会发觉就算服务端flush了,客户端还是会一直在read方法那里阻塞!具体原因各位可以看一下java api文档的截图:
文档说明了,如果流一直可用,而且没有读到流的末尾(就是对应着对方流已经关闭或者网络断开!),read会一直阻塞!其实这样做也是可以解释清楚的:本来服务端的read方法就不知道Server端的消息什么时候发送完,说不定我以为数据发送完 了,但其实是因为网络延迟而导致部分数据延后到来(况且也不可能所有数据同时到达),所以,read方法只能一直在阻塞等待对方的应答。所以,怎么实现长连接?
2、实现长连接的方法
A、客户端自动退出读取的动作。前面说了,就算服务端调用了flush方法进行输出刷新,客户端也不一定能退出read的动作,所以还是会阻塞。所以,退出动作必须有客户端程序自己完成,我们可以在服务端没发送完一段消息并且刷新前就进行一个写入结束符号的标志,客户端解析到结束符号时,变可直接退出read的循环读取操作,避免一直阻塞。
B、可以调用 读取一定字节到某个数组的read方法(不过好像这个不太行,毕竟每次消息的长度好像会变的),当然,这只是针对消息定长的情况。
下面贴上长连接实现后的代码(其实就是比前面的代码加多了读入结束标记符号)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
//发送核心方法 public String send(String send) throws IOException {
String rtn = null ;
BufferedWriter writer = null ;
OutputStreamWriter ow = null ;
OutputStream os = null ;
try {
os = socket.getOutputStream();
ow = new OutputStreamWriter(os);
writer = new BufferedWriter(ow);
char [] sendChar = send.toCharArray();
ArrayList<Integer> list = new ArrayList<Integer>();
for ( char ch:sendChar){
list.add(( int )ch);
}
//进行加密操作
list = encry(list);
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
writer.write(it.next());
}
//写入结束标志符号:%
writer.write( '%' );
writer.flush();
rtn = "发送成功!" ;
} finally {
//注意:直接关闭流将会导致socket关闭,只能通过shutdownOutput/input的方式关闭流
//另外,流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
// if(writer!=null){ // writer.close(); // } // if(ow!=null){ // ow.close(); // } // if(os!=null){ //os.close();
// } //socket.shutdownOutput();流关闭之后,相当于关闭底层的连接,除非新new个socket,否则和客户端的连接相当于断开
}
return rtn;
}
|
三、短连接
短连接就基本没什么好讲的啦,只是每次关闭Socket和流时需要注意一下事情:
1、虽然前面说了流关闭了,Socket就不可用了,但是,我们还是要显式的关闭Socket的,因为在Socekt中还有中状态:叫做半连接状态,当我们只是用到输出流的时候,我们关闭了输出流,并且不能直接调用close方法,只能调用shutDown对应方法(具体请查看java API),其实输入流还是连接着的(只是我们没有用到而已!),这时候,如果没有显式关闭Soceket,很容易导致内存泄露,所以,所有流Socket都要显式关闭
2、短连接和长连接有不同的用途:对于某次服务只需要一次回话的客户,使用短连接显得简单;但是,如果该次服务需要很多交互式的操作通信,那还是长连接比较高性能,毕竟,Socket的打开和关闭都是很耗性能的。
四、总结
1、对应流关闭,Socket的对应输入(出)数据的通道也就关闭,此时无法达到长连接效果;
2、关闭Socket,记得显式关闭流与socket,顺序是线管流再关socket.
3、要实先长连接,一般需要发送结束标记符号来告诉客户端服务端的某段消息已经发送完毕,否则客户端会一直阻塞在read方法。
好,长短连接的整理到这里,不足地方请各位大佬指正哈!
-
=
==
相关推荐
本文详细介绍了Java Socket长连接客户端和服务端的实现方式,包括了关键代码的解析和注意事项。通过这种方式,可以有效地提高网络通信的性能和稳定性。在实际项目中,可以根据具体需求进行适当的调整和完善。
"Java Socket 长连接实例"是关于如何实现一个持久连接的服务器和客户端程序的示例,这种连接能够保持开放,直到一方明确地关闭它。这在需要频繁通信或者需要长时间保持连接状态的应用场景中非常有用,比如聊天应用、...
总结,实现“Android-Socket长连接通信心跳包消息回调Java服务端”涉及了网络编程的多个关键点,包括Socket的创建和管理、心跳包的设计和处理、消息的异步回调以及服务端的并发处理。通过理论学习和实际项目的实践,...
以下是Socket长连接、心跳包和数据发送读取的关键知识点: 1. **TCP连接**:Socket基于传输层的TCP协议,提供可靠的双向通信。TCP保证了数据的顺序和完整性,通过三次握手建立连接,四次挥手断开连接。 2. **...
客户端使用Socket连接到服务器,创建一个输入流和一个输出流,用于数据的发送和接收。 2. **C/S架构**:C/S模式是一种常见的网络应用架构,由客户端(Client)和服务器端(Server)组成。客户端通常运行在用户的...
接着是`Connection.java`,它可能是代表单个Socket连接的类,具有以下组件和方法: 1. Socket实例:存储实际的Socket对象,用于数据传输。 2. 输入/输出流:通过`Socket`获取`InputStream`和`OutputStream`,用于...
总结起来,Java Socket编程中的长连接实现涉及TCP连接的创建、数据交换、心跳机制以及资源的管理和关闭。理解和掌握这些知识点对于开发高效、可靠的网络应用至关重要。在实际工作中,还需要考虑异常处理、线程安全...
在Java中,可以使用Apache Commons Pool库来实现Socket连接池,或者自定义一个基于LinkedList或ConcurrentHashMap的数据结构来管理和维护连接。同时,可以结合JMX(Java Management Extensions)进行监控,查看连接...
- **Android Socket编程**:使用Java的Socket类建立与NTRIP服务器的连接,收发数据。 - **JSON或XML解析**:NTRIP数据可能以这两种格式传输,需要解析成Java对象。 - **Android权限管理**:可能需要获取网络访问权限...
以上就是使用Java Socket编程实现文件上传涉及到的主要知识点,包括Socket通信机制、文件I/O、数据库操作、异常处理、多线程、安全性和性能优化等方面。理解并掌握这些内容,对于开发高效、可靠的文件上传系统至关...
Java Socket通信实现是网络编程中的一个关键概念,主要用于在两台计算机之间建立可靠的、双向的数据传输连接。在Java中,Socket类和ServerSocket类是进行网络通信的核心组件。本实例源码提供了关于如何使用Java ...
实现手机控制电脑端的部分,一般会涉及到移动设备的触摸事件转化为键盘鼠标事件模拟,这通常需要额外的协议设计和实现,例如将触摸事件转换为特定的控制指令,然后通过Socket发送到服务器,服务器再模拟这些操作。...
在本案例中,我们将关注如何使用Java Socket来实现SMTP(Simple Mail Transfer Protocol)邮件发送,并支持SSL(Secure Sockets Layer)和TLS(Transport Layer Security)安全协议。 SMTP是一种互联网标准,用于在...
Java的`java.sql.DriverManager`就提供了连接池的支持,但需要第三方库如Apache Commons Pool来实现Socket连接池。 9. **SSL/TLS安全通信** - Java提供`SSLSocket`和`SSLServerSocket`类支持安全的HTTPS通信,利用...
在实现这个系统时,我们还需要考虑以下关键点: - **错误处理**:网络通信中可能出现各种异常,如连接中断、数据传输错误等,需要通过try-catch语句进行捕获和处理。 - **数据格式化**:为了保证不同节点间的数据...
2. **InputStream和OutputStream的使用**:Socket连接建立后,可以通过`getInputStream()`和`getOutputStream()`方法获取输入流和输出流,分别用于读取服务器发送的数据和向服务器发送数据。 3. **连接管理和异常...
在实现心跳机制时,我们需要考虑以下几个关键点: 1. **心跳间隔**:心跳包的发送频率不宜过高,以免增加不必要的网络负担,但也不能过低,防止因网络延迟而误判连接中断。一般设置为几秒到几十秒不等。 2. **超时...
本教程主要探讨的是如何在Java中使用Socket实现多线程阻塞式通信,这通常涉及到服务器端(EchoServer)和客户端(EchoClient)的设计。在本文中,我们将详细解析`EchoServer.java`、`SocketUtils.java`和`EchoClient...
我们将会分析`EchoServer.java`、`EchoClient.java`和`SocketUtils.java`这三个文件中的关键知识点。 首先,让我们从`EchoServer.java`开始。这是一个典型的回显服务器,它的主要任务是接收客户端发送的数据并...
本示例将探讨如何在Java中实现长连接,并结合心跳检测来保持连接的活性。 首先,让我们了解TCP长连接的概念。TCP是一种面向连接的、可靠的传输协议,它会在数据传输前先建立连接,传输完成后断开连接。然而,对于...