TCP通信-群聊
Server
java
package TCP3;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class Server{
public static List<Socket> OnlineSockets = new ArrayList<>();
public static void main(String[] args) throws Exception{
System.out.println("...服务端启动成功...");
//1.创建ServerSocket的对象,同时为服务端注册端口
ServerSocket serverSocket = new ServerSocket(8888);
while (true) {
//2.使用serverSocket对象,调用一个accept方法,等待客户端连接请求
Socket socket = serverSocket.accept();
//添加在线Socket
OnlineSockets.add(socket);
//追踪客户端上限
System.out.println("有人上线了:"+ socket.getRemoteSocketAddress());
//3.把这个客户端对应的socket通信管道,交给一个独立的线程负责处理
new ServerReaderTread(socket).start();
}
}
}
创建服务端及其端口后,使用死循环与多个客户端链接,然后再分配子进程去管理这个客户端发来的消息
ServerReadTread
java
package TCP3;
import java.io.*;
import java.net.Socket;
public class ServerReaderTread extends Thread {
//线程变量
private Socket socket;
//有参构造器
public ServerReaderTread(Socket socket){
this.socket = socket;
}
public void run(){
//从socket通信管理中得到一个字节输入流
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true){
try {
String msg = dis.readUTF();
System.out.println(msg);
//把这个消息发给全部客户端进行接收
sendMsgToAll(msg);
} catch (IOException e) {
System.out.println("有人下线了:"+ socket.getRemoteSocketAddress());
//在在线Socket集合中删除对应端口
Server.OnlineSockets.remove(socket);
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void sendMsgToAll(String msg) throws IOException {
//发送给全部在线的socket管道接收
for (Socket onlineSocket : Server.OnlineSockets) {
OutputStream os = onlineSocket.getOutputStream();
DataOutputStream dos = new DataOutputStream(os);
dos.writeUTF(msg);
dos.flush();
}
}
}
客户端每与服务端连接,就会生成这个对应的子进程来管理,将输入字节流转换为数据流后,将其打印,跟踪客户端是否下线,最后将消息转发给所有在线的socket管道
Client
java
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{
//1.创建Socket对象,并同时请求与服务端的连接
Socket socket = new Socket("127.0.0.1",8888);
//创建一个独立的线程,负责随机从socket中接收服务端发送过来的消息
new ClientReaderTread(socket).start();
//2.从socket通信管道中得到一个字节输出流,用来发数据给服务端程序
OutputStream os = socket.getOutputStream();
//3.把低级的字节输出流包装成数据输出流
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println();
String msg = sc.nextLine();
//一旦用户输入了exit,就退出客户端程序
if("exit".equals(msg)){
System.out.println("已成功退出");
dos.close();
socket.close();
break;
}
//4.开始写数据出去了
dos.writeUTF(msg);
dos.flush();
}
}
}
创建客户端后,创建对应的客户端子进程用来接收信息,使用死循环不断将信息发送,
ClientReaderTread
java
package TCP3;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class ClientReaderTread extends Thread {
//线程变量
private Socket socket;
//有参构造器
public ClientReaderTread(Socket socket){
this.socket = socket;
}
public void run(){
try {
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true){
try {
String msg = dis.readUTF();
System.out.println(msg);
} catch (IOException e) {
System.out.println("自己下线了:"+ socket.getRemoteSocketAddress());
dis.close();
socket.close();
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
也是从通信管道中获取这个信息输入流,然后将其打印出来