参考: 1、Java Socket编程—-通信是这样炼成的 2、TCP传输模式中,调用Socket的shutdownInput()和shutdownOutput()都做了些什么?
1、Socket编程 IP+Port组成了所谓的Socket,Socket是网络上运行的程序之间双向通信链路的终结点,是TCP和UDP的基础。 1.1、Socket套接字: 网络上具有唯一标识的IP地址和端口组合在一起才能构成唯一能识别的标识符套接字。 1.2、Socket原理机制: 通信的两端都有Socket
网络通信其实就是Socket间的通信
数据在两个Socket间通过IO传输
2、TCP编程
1、TCP协议是面向连接的、可靠的、有序的、以字节流的方式发送数据,通过三次握手方式建立连接,形成传输数据的通道,在连接中进行大量数据的传输,效率会稍低。
2、Java中基于TCP协议实现网络通信的类
- 客户端的Socket类
① 创建ServerSocket对象,绑定监听端口 ② 通过accept()方法监听客户端请求 ③ 连接建立后,通过输入流读取客户端发送的请求信息 ④ 通过输出流向客户端发送乡音信息 ⑤ 关闭相关资源
public static void test00() throws IOException{
//1、服务端监听指定端口
ServerSocket serverSocket = new ServerSocket(10007);
//2、获取socket, accept是阻塞方法
Socket socket = serverSocket.accept();
//3、通过输入输出流
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
//4、通过输入流读取信息
byte[] buf = new byte[1024];
int len = 0;
len = in.read(buf);
System.out.println("服务端接收到数据" + new String(buf, 0, len));
//4、通过输出流发送信息
out.write("ok".getBytes());
out.close();
//5、关闭相关资源。
socket.close();
serverSocket.close();
}
4、Socket客户端
① 创建Socket ② 打开连接到Socket的输入/输出流 ③ 按照协议对Socket进行读/写操作 ④ 关闭输入输出流、关闭Socket
public static void test00() throws UnknownHostException, IOException {
//1、创建Socket
Socket socket = new Socket("localhost", 10007);
//2、通过Socket获取输入输出流
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
//3、客户端向服务端发送数据
out.write("Im a client".getBytes());
out.flush();
//3、接收服务端的响应, 通过一个buffer读取服务端的消息。
byte[] buf = new byte[1014];
int len = 0;
len = in.read(buf);
System.out.println("client 接收到数据:" + new String(buf, 0, len));
//4、关闭资源
socket.close();
}
上面通过一个buffer获取读取的信息,
//3、接收服务端的响应, 通过一个buffer读取服务端的消息。
byte[] buf = new byte[1014];
int len = 0;
len = in.read(buf);
System.out.println("client 接收到数据:" + new Stri
在此处,稍做修改,使用逐个字节读取
5.1、客户端
java.net.SocketException: Connection reset
, 客户端报错java.net.SocketTimeoutException: Read timed out
。
java.net.SocketException: (Connection reset或者Connect reset by peer:Socket write error)。该异常在客户端和服务器端均有可能发生,引起该异常的原因有两个,第一个就是如果一端的Socket被关闭(或主动关闭或者因为异常退出而引起的关闭),另一端仍发送数据,发送的第一个数据包引发该异常(Connect reset by peer)。另一个是一端退出,但退出时并未关闭该连接,另一端如果在从连接中读数据则抛出该异常(Connection reset)。简单的说就是在连接断开后的读和写操作引起的。
5.5、解决方案
5.5.1、使用 socket.shutdownInput();
(服务端), 和socket.shutdownOutput();
(客户端)。
关于shutdownOutput(), shutdownInput(): 在客户端或者服务端通过socket.shutdownOutput()都是单向关闭的,即关闭客户端的输出流并不会关闭服务端的输出流,所以是一种单方向的关闭流; 通过socket.shutdownOutput()关闭输出流,但socket仍然是连接状态,连接并未关闭 如果直接关闭输入或者输出流,即:in.close()或者out.close(),会直接关闭socket
6、基于字符流 6.1、服务端public static void test02() throws IOException {
/**
* 基于TCP协议的Socket通信,实现用户登录,服务端
*/
//1、创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
ServerSocket serverSocket =new ServerSocket(10086);//1024-65535的某个端口
//2、调用accept()方法开始监听,等待客户端的连接
Socket socket = serverSocket.accept();
//3、获取输入流,并读取客户端信息
InputStream is = socket.getInputStream();
InputStreamReader isr =new InputStreamReader(is);
BufferedReader br =new BufferedReader(isr);
String info =null;
while((info=br.readLine())!=null){
System.out.println("我是服务器,客户端说:"+info);
}
socket.shutdownInput();//关闭输入流
//4、获取输出流,响应客户端的请求
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("欢迎您!");
pw.flush();
//5、关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
}
6.2、客户端
public static void test02() throws IOException{
//客户端
//1、创建客户端Socket,指定服务器地址和端口
Socket socket =new Socket("localhost",10086);
//2、获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();//字节输出流
PrintWriter pw =new PrintWriter(os);//将输出流包装成打印流
pw.write("用户名:admin;密码:123");
pw.flush();
socket.shutdownOutput();
//3、获取输入流,并读取服务器端的响应信息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while((info=br.readLine())!=null){
System.out.println("我是客户端,服务器说:"+info);
}
//4、关闭资源
br.close();
is.close();
pw.close();
os.close();
socket.close();
}
同样需要使用shutdownOutput, shutdownInput.