概述
Socket编程是指编写在多台计算机上执行的程序,其中的设备都使用网络相互连接
Socket常用的通信协议有UDP和TCP,本文主要介绍通过TCP/IP网络协议进行Socket编程
Socket通信流程
- 服务端和客户端初始化
socket
,得到文件描述符; - 服务端调用
bind
,将绑定在 IP 地址和端口; - 服务端调用
listen
,进行监听; - 服务端调用
accept
,等待客户端连接; - 客户端调用
connect
,向服务器端的地址和端口发起连接请求; - 服务端
accept
返回用于传输的socket
的文件描述符; - 客户端调用
write
写入数据;服务端调用read
读取数据; - 客户端断开连接时,会调用
close
,那么服务端read
读取数据的时候,就会读取到了EOF
,待处理完数据后,服务端调用close
,表示连接关闭;
服务端调用 accept
时,连接成功了会返回一个已完成连接的 socket,后续用来传输数据。所以,监听的 socket 和真正用来传送数据的 socket,是「两个」 socket,一个叫作监听 socket,一个叫作已完成连接 socket。
简单示例
Socket是网络上不同计算机运行的两个程序之间双向通信链路的一个端点。Socket需要绑定端口号,一遍传输层可以标识数据要发送到的应用程序
服务端
服务端会用到两个socket,一个叫作监听 socket,一个叫作已完成连接 socket
目前的服务器不能保证通信的连续性,它会在发送完消息后关闭连接
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
// socket服务端
public class Server {
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void start(int port){
try{
// (监听socket)
// 绑定指定端口,使服务器的Socket在指定端口号上运行
serverSocket = new ServerSocket(port);
// (已连接socket)
// 服务器遇到accept进入阻塞,等待客户端发出连接
// 连接成功后,服务器将获得绑定到同一本地端口6666的新socket,用于传输数据
clientSocket = serverSocket.accept();
// 输出流,可发送消息到客户端
out = new PrintWriter(clientSocket.getOutputStream(), true);
// 输入流,可接收客户端消息
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String greeting = in.readLine();
if(greeting.equals("hello server")){
out.println("hello client");
}
else{
out.println("unrecognised greeting");
}
}
catch (IOException e){
e.printStackTrace();
}
}
public void stop(){
try{
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
catch (IOException e){
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
// 开启服务器
server.start(6666);
}
}
客户端
客户端只需要创建一个socket以保持连接,最终客户端的输入流连接到服务端的输出流,服务器的输入流连接到客户端的输出流
import com.sun.javafx.iio.ios.IosDescriptor;
import java.io.*;
import java.net.Socket;
public class Client {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void startConnection(String ip, int port){
try{
// 客户端需要知道服务端的ip和其正在监听的端口号,才能发起连接
// 服务器接收连接后创建客户端socket
clientSocket = new Socket(ip, port);
// 获取socket的输入输出流,以便与服务端通信
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
catch (IOException e){
e.printStackTrace();
}
}