1.说明
Socket(套接字)是计算机网络编程中用于实现网络通信的一种编程接口或抽象概念。
它提供了一种标准的接口,使应用程序能够通过网络与其他计算机进行通信。
Socket可以看作是应用程序与网络之间的一个通信端点,类似于电话中的插座。
通过Socket,应用程序可以创建、连接、发送和接收数据,以实现网络通信。
Socket通常使用TCP/IP协议栈作为底层网络协议,
但也可以与其他协议一起使用,
如UDP(User Datagram Protocol)和ICMP(Internet Control Message Protocol)等。
Java中基于TCP协议实现网络通信的类
- 客户端的Socket类
- 服务器端的ServerSocket类
服务端和客户端使用Socket通信的步骤:
- 创建ServerSocket和Socket
- 打开连接到Socket的输入/输出流
- 按照协议对Socket进行读/写操作
- 关闭输入输出流、关闭Socket
2.服务端编程
服务端使用ServerSocket编程步骤:
- 创建ServerSocket对象,绑定监听端口
- 通过accept()方法监听客户端请求
- 连接建立后,通过输入流读取客户端发送的请求信息
- 通过输出流向客户端发送乡音信息
- 关闭相关资源
package edu.java.net.socket.tcp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP Socket 套接字服务端
*/
public class ServerSocketDemo {
public static void main(String[] args) throws Exception {
// simpleServer();
concurrentServer();
}
/**
* 单线程服务端,只能接收一个客户端的请求,并且会话结束后服务端自动停止
*/
public static void simpleServer() throws IOException {
// 基于TCP协议的Socket通信,实现用户登录,服务端
// 1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口
// 1024-65535的某个端口
ServerSocket serverSocket = new ServerSocket(10086);
System.out.println("服务端已经启动,等待客户端的连接...");
// 2.调用accept()方法开始监听,等待客户端的连接
// 进程阻塞直到接收到客户端请求
Socket socket = serverSocket.accept();
// 3.获取输出流,响应客户端的请求
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("欢迎您访问服务端!" + System.lineSeparator());
pw.flush();
// 4.获取输入流,并读取客户端信息
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);
pw.write("服务端收到:" + info + System.lineSeparator());
}
pw.flush();
// 关闭输入流
socket.shutdownInput();
// 5.关闭资源
pw.close();
os.close();
br.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
}
}
3.客户端编程
客户端使用Socket编程步骤:
- 创建Socket对象,指明需要连接的服务器的地址和端口号
- 连接建立后,通过输出流想服务器端发送请求信息
- 通过输入流获取服务器响应的信息
- 关闭响应资源
package edu.java.net.socket.tcp;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
/**
* TCP Socket 套接字客户端
*
*/
public class ClientSocketDemo {
public static void main(String[] args) throws Exception {
// 1.创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("localhost", 10086);
// 2.获取输出流,向服务器端发送信息
OutputStream os = socket.getOutputStream();
// 字节输出流
PrintWriter pw = new PrintWriter(os);
// 将输出流包装成打印流
// 注意结尾的换行,提示服务端一行结束
pw.write("用户名:admin" + System.lineSeparator());
pw.write("密码:123456" + System.lineSeparator());
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();
}
}
4.服务端多线程编程
实际场景中,一个服务端往往可以支持多个客户端的连接,为多个客户端提供服务。
实现服务器与多客户端之间的通信步骤:
- 服务器端创建ServerSocket,循环调用accept()等待客户端连接
- 客户端创建一个socket并请求和服务器端连接
- 服务器端接受客户端请求,创建socket与该客户建立专线连接
- 建立连接的两个socket在一个单独的线程上通信
- 服务器端继续等待新的连接
package edu.java.net.socket.tcp;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP Socket 套接字服务端
*/
public class ServerSocketDemo {
public static void main(String[] args) throws Exception {
concurrentServer();
}
/**
* 多线程服务端,能同时接收多个客户端的请求,并且会话结束后关掉对应Socket通道,服务端继续运行
*/
public static void concurrentServer() {
int count = 0;
try {
@SuppressWarnings("resource")
ServerSocket serverSocket = new ServerSocket(10086);
while (true) {
System.out.println("服务端已经启动,等待客户端的连接...");
Socket socket = serverSocket.accept();
count++;
System.out.println("监听到客户端的连接数量=" + count);
// 启动一个线程
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 服务器多线程处理的实际线程类
class ServerThread extends Thread {
private int serverName = this.hashCode();
// 和本线程相关的socket
private Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
// 1.获取输出流,响应客户端的请求
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write(serverName + ">欢迎您访问服务端!" + System.lineSeparator());
pw.flush();
// 2.获取输入流,并读取客户端信息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String info = null;
while ((info = br.readLine()) != null) {
System.out.println(serverName + ">服务端接收到消息:" + info);
pw.write("服务端收到:" + info + System.lineSeparator());
}
pw.flush();
socket.shutdownInput();
// 3.关闭资源
pw.close();
os.close();
br.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}