Java网络编程之(二): TCP的多线程连接
相比前面一个例子,这里加入了多线程的操作,服务器可以不断读取客户端数据,并向客户端写入数据;客户端也可以不断的读取服务器数据,并向服务器写入数据。支持多客户端,功能实际就是一个基于Socket的TCP简易聊天程序,服务端实现了消息的转发。
局域网中电脑A用作服务端,IP为192.168,31.168
同时电脑A中开启另一个终端作为一个客户端
电脑B用作客户端,IP为192.168.31.132
一. TcpServer_2.java
import java.net.ServerSocket;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
public class TcpServer_2
{
//定义保存所有Socket的ArrayList
public static ArrayList<Socket> socketList = new ArrayList<Socket>();
public static void main(String[] args)throws IOException
{
ServerSocket ss = new ServerSocket(30001);
while(true)
{
//此行代码会阻塞,将一直等待别人的连接
Socket s = ss.accept();
socketList.add(s);
//每当客户端连接后,启动一条ServerThread线程为该客户端服务
new Thread(new ServerThread(s)).start();
}
}
}
二. ServerThread.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
//负责处理每个线程通信的线程类
public class ServerThread implements Runnable
{
//定义当前线程所处理的Scoket
Socket s = null;
//该线程所处理的Socket所对应的输入流
BufferedReader br = null;
public ServerThread(Socket s) throws IOException
{
this.s = s;
//初始化该Socket对应的输入流
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
public void run()
{
try
{
String connect = null;
//采用循环不断从Socket中读取客户端送过来的数据
while((connect = readFromClient()) != null)
{
//遍历socketList中的每个Socket,将读到的内容向每个Socket发送一次
for(Socket s: TcpServer_2.socketList)
{
PrintStream ps = new PrintStream(s.getOutputStream());
ps.println(connect);
}
}
}catch(IOException e)
{
e.printStackTrace();
}
}
//定义读取客户端数据的方法
private String readFromClient()
{
try
{
return br.readLine();
}
//如果捕捉到异常,表明该Socket对应的客户端已经关闭
catch(IOException e)
{
//删除该Socket
TcpServer_2.socketList.remove(s);
}
return null;
}
}
三. TcpClient_2.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.io.IOException;
public class TcpClient_2
{
public static void main(String[] args) throws IOException
{
Socket s = new Socket("192.168.31.168", 30001);
//客户端启动ClientThread线程不断读取来自服务器的数据
new Thread(new ClientThread(s)).start();
//获取该Socket对应的输出流
PrintStream ps = new PrintStream(s.getOutputStream());
String line = null;
//不断读取键盘输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
while((line=br.readLine()) != null)
{
//将用户的键盘输入内容写入Socket对应的输出流
ps.println(line);
}
}
}
四. ClientThread.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class ClientThread implements Runnable
{
//该线程负责处理的Socket
private Socket s;
//该线程所处理的Socket所对应的输入流
BufferedReader br = null;
public ClientThread(Socket s)throws IOException
{
this.s = s;
br = new BufferedReader(new InputStreamReader(s.getInputStream()));
}
public void run()
{
try
{
String connect = null;
//不断读取Socket输入流中的内容,并将这些内容打印输出
while((connect = br.readLine()) != null)
{
System.out.println(connect);
}
}catch(Exception e)
{
e.printStackTrace();
}
}
}
五.编译:
因为有多个java文件,所以用javac *.java编译
六. 运行结果
电脑A先运行服务端:
电脑A开另外一个终端运行客户端,电脑B也运行一个客户端:
实际测试,运行多个客户端也是可以的,只要有一个客户端发消息,其它客户端都会收到。服务端也起到一个消息转发的作用。