一、基于TCP的Socket通信
1、TCP协议:TCP协议是面向连接的、可靠的、有序的,以字节流方式传输数据的通信协议。客户端与服务器要想实现通信,首先需要建立连接。
2、Java提供的基于TCP协议实现网络通信的类为:客户端的Socket类、服务器端的ServerSocket类。
3、Socket通信模型,见下图(摘自慕课网)
4、Socket通信的实现步骤:
(1)创建ServerSocket和Socket对象
(2)打开Socket的输入/输出流
(3)从输入/输出流中读/写数据
(4)关闭相关资源
二、Socket编程实例
1、非多线程的情况
服务器端:
ServerDemo.java
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket server = null;
Socket client = null;
InputStream in = null;
InputStreamReader reader = null;
BufferedReader bufReader = null;
OutputStream out = null;
PrintWriter writer = null;
try {
//1、创建服务器端socket,并绑定9999端口,绑定端口之后,服务器一直监听9999端口的请求
server = new ServerSocket(9999);
System.out.println("------服务器已启动,等待客户端信息------");
//2、服务器端接收到客户端的请求,建立连接
client = server.accept();
//3、将客户的请求数据以输入流的形式读取出来
in = client.getInputStream();
reader = new InputStreamReader(in);
bufReader = new BufferedReader(reader);
String msg = null;
while((msg = bufReader.readLine()) != null) {
System.out.println("收到客户端的信息:" + msg);
}
//4、关闭输入流
client.shutdownInput();
//5、通过输出流向客户端发送信息
out = client.getOutputStream();
writer = new PrintWriter(out);
writer.write("我是服务器,我已经收到了你的信息!");
writer.flush();
//6、关闭输出流
client.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
//7、程序最后一定要关闭资源
if(in != null)
in.close();
if(reader != null)
reader.close();
if(bufReader != null)
bufReader.close();
if(out != null)
out.close();
if(writer != null)
writer.close();
if(client != null)
client.close();
if(server != null)
server.close();
}
}
}
客户端:
ClientDemo.java
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket client = null;
InputStream in = null;
InputStreamReader reader = null;
BufferedReader bufReader = null;
OutputStream out = null;
PrintWriter writer = null;
try {
//1、新建客户端socket,指明需要连接的服务器地址和端口号
//如果是本机,地址可以是localhost或者127.0.0.1
client = new Socket("localhost", 9999);
System.out.println("------客户端准备与服务器端建立连接------");
//2、建立连接后通过输出流向服务器端发送信息
out = client.getOutputStream();
writer = new PrintWriter(out);
writer.write("我是客户端,你收到我的请求了吗?");
writer.flush();
//3、关闭输出流
client.shutdownOutput();
//4、将服务器端的响应以输出流的形式读取出来
in = client.getInputStream();
reader = new InputStreamReader(in);
bufReader = new BufferedReader(reader);
String msg = null;
while((msg = bufReader.readLine()) != null) {
System.out.println("收到服务器的应答:" + msg);
}
//5、关闭输出流
client.shutdownInput();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//6、程序的最后一定要关闭资源
if(in != null)
in.close();
if(reader != null)
reader.close();
if(bufReader != null)
bufReader.close();
if(out != null)
out.close();
if(writer != null)
writer.close();
if(client != null)
client.close();
}
}
}
2、多线程的情况(即一个服务器端可以不断接收多个客户端的请求)
服务器端入口:
ServerThreadMain.java
public class ServerThreadMain {
public static void main(String[] args) {
ServerSocket server = null;
Socket client = null;
try {
server = new ServerSocket(9999);
System.out.println("------服务器已启动,等待客户端信息------");
while(true) {
client = server.accept();
ServerThread thread = new ServerThread(client);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里写了一个死循环,代表服务器端一直接收客户端的请求,每接收到一个客户端请求,服务器端会新启一个线程进行处理。
代表服务器端核心处理的线程:
ServerThread.java
public class ServerThread extends Thread {
public Socket client;
public ServerThread(Socket client) {
this.client = client;
}
public void run() {
InputStream in = null;
InputStreamReader reader = null;
BufferedReader bufReader = null;
OutputStream out = null;
PrintWriter writer = null;
try {
in = client.getInputStream();
reader = new InputStreamReader(in);
bufReader = new BufferedReader(reader);
String msg = null;
while((msg = bufReader.readLine()) != null) {
System.out.println("收到客户端的信息:" + msg);
}
client.shutdownInput();
out = client.getOutputStream();
writer = new PrintWriter(out);
writer.write("我是服务器,我已经收到了你的信息!");
writer.flush();
client.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(in != null)
in.close();
if(reader != null)
reader.close();
if(bufReader != null)
bufReader.close();
if(out != null)
out.close();
if(writer != null)
writer.close();
if(client != null)
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端代码与非多线程的客户端代码相同,不再赘述。