上一篇文章里面介绍了JAVA Socket编程入门简介,在示例中介绍了服务端和客户端之间的通信和交互,这个示例中服务端一次只能接受一个客户的连接,这显然不能满足我们对Socket编程的探索。今天我们将讲解一些稍微复杂一些的案例,在这个案例中服务端能接受数个客户的连接,并对某个客户发来的消息转发给所有的客户端(有点类似QQ群的功能,一个人说话,大家都能看到)。
开发原理
建立服务端: 使用ServerSocket监听指定的端口,并新建一个Socket的List用来存放所有跟服务端连接的客户建立的Socket。对于每一个连接的客户都使其在单独的一个线程中与服务端进行通信传输消息,并从Socket List中读取所有的客户建立的socket转发此消息。
服务端涉及到两个类:Chat和ChatServer。ChatServer用来对每个客户建立与服务端的连接并为其分配一个线程与服务端进行通信,并在Chat中进行转发客户的消息。
public class ChatServer{
public void startWork() throws IOException{
ServerSocket ss = new ServerSocket(1234);
List<Socket> socketList = new ArrayList<Socket>();
Socket socket = null;
int count = 0;
while( true){
socket = ss.accept();
count++;
System. out.println(count + " client connected to the server!");
socketList.add(socket);
new Chat(socket, socketList, count).start();
}
}
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ChatServer cs = new ChatServer();
cs.startWork();
}
}
public class Chat extends Thread {
private Socket socket;
private List<Socket> socketList;
private int count = 0;
public Chat(Socket socket, List<Socket> socketList , int count){
this. socket = socket;
this. socketList = socketList;
this. count = count;
}
@Override
public void run() {
BufferedReader reader = null;
PrintWriter writer = null;
try{
reader = new BufferedReader( new InputStreamReader(socket.getInputStream()));
String message = null;
while( true){
message = reader.readLine();
if( "bye".equals(message)){
writer = new PrintWriter(socket.getOutputStream());
writer.println("bye");
writer.flush();
continue;
}
for( int i = 0; i< socketList.size(); i++){
writer = new PrintWriter(socketList.get(i).getOutputStream());
writer.println(count + " say:" + message);
writer.flush();
}
}
} catch(IOException e){
e.printStackTrace();
}
}
}
建立客户端:客户端只要包括两个功能:给服务端发消息,接受服务端转发的其他客户发送的消息。服务端涉及到类ChatClient,在这个类中分别新建了两个内部类来处理发送和接受服务端的消息。
class ReadMes extends Thread{
private Socket socket;
public ReadMes(Socket socket){
this. socket = socket;
}
@Override
public void run() {
BufferedReader reader = null;
try{
reader = new BufferedReader( new InputStreamReader(socket .getInputStream()));
String message = null;
while( true){
message = reader.readLine();
if( "bye".equals(message)){
break;
}
System. out.println(message);
}
} catch(IOException e){
e.printStackTrace();
} finally{
if( reader!= null){
try {
reader.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
class SendMes extends Thread{
private Socket socket;
public SendMes(Socket socket){
this. socket = socket;
}
@Override
public void run() {
BufferedReader input = null;
PrintWriter writer = null;
try{
input = new BufferedReader( new InputStreamReader(System.in ));
writer = new PrintWriter( socket.getOutputStream());
String message = null;
while( true){
message = input.readLine();
if( "bye" .equals(message)){
break;
}
writer.println(message);
writer.flush();
}
} catch(IOException e){
e.printStackTrace();
} finally{
if(input!= null){
try {
input.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class ChatClient {
public void startWork() throws UnknownHostException, IOException{
Socket socket = new Socket( "127.0.0.1" , 1234);
new ReadMes(socket).start();
new SendMes(socket).start();
}
/**
* @param args
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
ChatClient cc = new ChatClient();
cc.startWork();
}
}
程序运行结果:
在命令行下首先编译代码,然后运行服务端代码,然后另外打开两个命令行窗口作为两个客户连接服务端并运行客户端代码,运行结果如下图所示。