提示:本文是记录学习java tcp通信的一些笔记
前言
本文是学习java tcp通信的一些笔记
一、 Socket介绍
Socket(套接字)是网络通信的一个端点,它允许两个设备(例如计算机、服务器等)之间进行数据传输。因为tcp通信的特点是有连接(就是发消息前要先建立连接),可靠的(有一些确保双方能收到消息的机制),全双工的,所以可以把JavaTCP通信想象成客户端和服务端之间用一个电话线连起来,在电话线两端通过手上拿听筒进行向对方讲话,自己向对方发送消息,也可以拿听筒听对方讲话,自己接收对方消息。而Socket就是通电话双方各自手上拿的听筒。通过Socket的OutputStream输出流你可以沿着电话线向对方发送消息,也可以通过Socket的InputStream输入流接收对方消息。在客户端通过创建Socket的到Socket,服务端通过创建ServeSocket对象然后通过其accept阻塞方法和客户端建立连接后得到服务端的Socket方法。通信结束时,客户端和服务器都需要关闭Socket,以释放资源。
Socket相关代码如下
客户端
import java.net.Socket;
//客户端
public class Client {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1", 8888);
System.out.println("连接到服务器:" + socket.getRemoteSocketAddress());//获取服务端的ip地址端口号
System.out.println("客户端IP地址:" + socket.getLocalAddress());
System.out.println("客户端端口号:" + socket.getLocalPort());
System.out.println("服务器IP地址:" + socket.getInetAddress());
System.out.println("服务器端口号:" + socket.getPort());
}
}
服务端
//服务端
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器启动,等待客户端连接...");
while (true) {
Socket socket = serverSocket.accept();
System.out.println("客户端连接:" + socket.getRemoteSocketAddress());//获取客户端的ip地址和端口,例如客户端连接:/192.168.1.100:54321
System.out.println("客户端IP地址:" + socket.getInetAddress());
System.out.println("客户端端口号:" + socket.getPort());
System.out.println("服务器IP地址:" + socket.getLocalAddress());
System.out.println("服务器端口号:" + socket.getLocalPort());
}
}
}
二、使用javaTcp通信实现多个客户端通信案例
具体代码实现
- 服务器端代码
Server类:
创建ServerSocket:在端口8888上创建一个ServerSocket实例,用于监听客户端的连接请求。接受客户端连接:在一个无限循环中,调用accept方法等待客户端连接。当有客户端连接时,accept方法返回一个新的Socket实例。这个实例是服务端的,这个socket它能够对应的客户端的socket实例相连接进行通信,和记录客户端连接:将新连接的Socket实例添加到onlineSockets列表中,以便后续管理所有在线客户端。启动线程处理客户端通信:为每个新连接的客户端创建一个ServerReaderThread线程实例,并启动该线程,处理客户端的通信。
import java.util.List;
public class Server {
public static List<Socket> onlineSockets = new ArrayList<>();
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888) ;
while (true) {
Socket socket = serverSocket.accept() ;
System.out.println(socket.getRemoteSocketAddress()+"上线了");
onlineSockets.add(socket);
new ServerReaderThread(socket).start();
}
}
}
ServerReaderThread类:
构造函数:接收一个Socket实例,并将其赋值给成员变量socket。
run方法:在一个无限循环中,读取客户端发送的消息,并将消息转发给所有在线客户端。
读取消息:通过DataInputStream读取客户端发送的消息。
转发消息:调用sendAllClient方法,将消息转发给所有在线客户端。
异常处理:处理客户端断开连接和其他IO异常,关闭相关资源。
package tcp3;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
DataInputStream dis = new DataInputStream(socket.getInputStream());
String msg = null;
try {
msg = dis.readUTF();
System.out.println(msg);
sendAllClient(msg);
} catch (IOException e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
dis.close();
socket.close();
break;
}
} catch (IOException e) {
System.out.println("文件异常");
}
}
}
- 客户端代码
Client类:
创建Socket:连接到服务器的IP地址127.0.0.1和端口8888。
启动线程处理服务器消息:创建并启动ClientReaderThread线程实例,处理服务器发送的消息。
发送消息:在一个无限循环中,读取用户输入的消息,并通过DataOutputStream发送到服务器。
退出条件:当用户输入"exit"时,关闭输出流和Socket连接,退出循环。
ClientReaderThread类:
package tcp3;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws Exception{
Socket socket = new Socket("127.0.0.1",8888);
new ClientReaderThread(socket).start();
OutputStream os = socket.getOutputStream();
DataOutputStream dos =new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.print("请输入:");
String msg = sc.next();
if ("exit".equals(msg)) {
dos.close();
socket.close();
break;
}
dos.writeUTF( msg);
dos.flush();
}
}
}
ClientReaderThread 构造函数:接收一个Socket实例,并将其赋值给成员变量socket。
run方法:在一个无限循环中,读取服务器发送的消息,并将消息打印到控制台。
读取消息:通过DataInputStream读取服务器发送的消息。
异常处理:处理服务器断开连接和其他IO异常,关闭相关资源。
package tcp3;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class ClientReaderThread extends Thread{
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
while (true) {
try {
DataInputStream dis = new DataInputStream(socket.getInputStream());
String msg = null;
try {
msg = dis.readUTF();
System.out.println(msg);
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress()+"下线了");
dis.close();
socket.close();
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
注意事项
运行多次Client类时候先点击idea右上角编辑配置—>修改选项---->允许多个实例----->应用---->确定
总结
主要思路是使用服务端做中介转发客户端的消息达到多个客户端可以相互通信的效果。