Socket是什么

Socket是什么

期末终于考完啦,接下来这段时间的空闲就比较多了,应该会进入一个比较高速的更新期,在上一篇了解了计算机网络的基本架构后,我们今天来看一看如何用Socket实现一个简单的网络通讯

Socket是什么东西?如果你打开翻译。会发现这个单词的大概释义是插头,插座等等,一般在计算机语境下我们将其翻译为套接字(这个翻译真的是难以评价,丝毫不能体现其实际作用),也就是一套事先约定的计算机间进行网络通信的一套协议,支持TCP和UDP(Java中的Socket是基于TCP的)。今天我们将会使用这一套协议实现一个简单的群聊,并通过这个过程来初步了解Socket

建立连接

在实现聊天之前,我们首先要建立一个连接

要建立一个连接,我们需要一个服务端来监听与处理请求,一个客户端来发起请求,先来完成服务端

1
2
3
4
5
6
7
8
9
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server started");
System.out.println("等待对方加入");
Socket socket = serverSocket.accept();
System.out.println("有用户加入"+socket.getInetAddress().getHostAddress());
Thread.sleep(1000);//保持连接
System.out.println("连接结束");
}

我们一个个来解释

1
ServerSocket serverSocket = new ServerSocket(8888);

ServerSocket对象会持续的监听对应端口.即8888端口,检查是否有链接请求(如果不知道端口等相关知识,请阅读走进网络世界 - Soul的小站 (soulmate.org.cn))

1
Socket socket = serverSocket.accept();

这个方法是阻塞的,当监听到连接请求时accept方法会同意连接并将这个连接包装为一个Socket对象,接下来我们的一切通讯都将通过这个对象进行

接下来我们完成客户端

1
2
3
4
5
 public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
System.out.println("成功连接到"+socket.getRemoteSocketAddress());
socket.close();
}
1
Socket socket = new Socket("127.0.0.1",8888);

向IP为127.0.0.1的8888端口发送请求建立连接,127.0.0.1是回环地址,即向本地发起连接请求

怎么样是不是很简单(把上面的两个main方法分别放在两个类中就可以运行了)

实现信息传输

要实现信息传输,就要用到IO流,关于IO流(Java中的IO流 - Soul的小站 (soulmate.org.cn))

此外,我们要实现收发消息的的异步,所以最好是有两个独立的线程来负责消息的收发,(Java多线程 - Soul的小站 (soulmate.org.cn))

我们将代码稍加完善就可以得到

服务端

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class Main {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("Server started");
System.out.println("如需退出请输入exit");
System.out.println("等待对方加入");
Socket socket = serverSocket.accept();
System.out.println("有用户加入"+socket.getInetAddress().getHostAddress());
Thread t1=new Thread(()->{
BufferedReader br=null;
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
try {

while(!Thread.currentThread().isInterrupted()) {

String msg= br.readLine();
System.out.println(socket.getInetAddress().getHostAddress()+":"+msg);
}
} catch (IOException e) {
System.out.println("连接异常,可能为对方断开连接");
}

});
Thread t2=new Thread(()->{
BufferedWriter bw=null;
try{
bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(true){
Scanner scanner = new Scanner(System.in);
String input=scanner.nextLine();
if(input.equals("exit")){
t1.interrupt();//通过中断机制同时结束所有线程
break;
}
bw.write(input);
bw.flush();
}
}catch (IOException e){
System.out.println("发送异常");
}finally {

try {
socket.close();
serverSocket.close();
} catch (IOException e) {
System.out.println("未知异常");
}
}
});
t1.start();
t2.start();
}
}

客户端

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class Main {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8888);
System.out.println("成功连接到"+socket.getRemoteSocketAddress());
System.out.println("如需退出请输入exit");

Thread t1=new Thread(()->{
BufferedReader br=null;
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
String msg=null;
while(!Thread.currentThread().isInterrupted()){
try {
msg= br.readLine();
} catch (IOException e) {
System.out.println("连接断开");
}
System.out.println(socket.getRemoteSocketAddress()+":"+msg);
}

});
Thread t2=new Thread(()->{
BufferedWriter bw=null;
try{
bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner=new Scanner(System.in);
while(true){
String input=scanner.nextLine();
if(input.equals("exit")){
t1.interrupt();//通过中断机制同时结束所有线程
break;
}
bw.write(input+"\n");
bw.flush();
}
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
socket.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
t1.start();
t2.start();

}
}

上面的代码中我们使用了缓冲流以提高性能,当然由于没有仔细涉及,这部分代码需要改进的地方还是挺多的

实现群聊

其实写到这里我相信你也可以独立的实现一个群聊了,这里我就不具体的写实现了,你可以试着自己完成(最好完善我上面代码的异常处理机制)

提示:不一定要在我给出的代码的基础上修改,你可以自己从头重新实现

关于UDP

既然Socket默认是使用TCP进行通信的,那么我们有改如何实UDP通信呢,我们可以使用DatagramSocketDatagramPacket两个类来实现

修改服务端

1
2
3
4
DatagramSocket socket = new DatagramSocket(8888);
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
socket.receive(packet); // 接收数据包

修改客户端

1
socket = new DatagramSocket("127.0.0.1"8888);

剩下的就没什么区别了,完全可以和一般的Socket以同种方法使用

补充

实际上Socket类中的方法还是很丰富的,但是这些方法与我们无关,我们只需要建立连接,然后用IO流实现信息的传输即可。当然,从使用的角度来说了解这些就足够了,但是作为一个有远大志向的码农,我们最好还是学习一下TCP和UDP的具体实现过程,感兴趣的可以自行了解,我在这里就不过多的讲了


Socket是什么
http://soulmate.org.cn/2025/01/16/Socket是什么/
作者
Soul
发布于
2025年1月16日
许可协议