服务器端使用ServerSocket类,需要调用accept()方法阻塞线程,所以不应放在main方法中,我们新建一个ServerListener类用来监听客户端的连接。
MyServer类
package socket.server;
public class MyServerSocket {
public static void main(String[] args) {
// TODO Auto-generated method stub
<span style="white-space:pre"> </span>//匿名类调用ServerListener的run()方法
new ServerListener().start();
}
}
ServerListener类,继承Thread类
package socket.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerListener extends Thread {
@SuppressWarnings("resource")
@Override
public void run() {
ServerSocket mServerSocket = null;
Socket socket = new Socket();
// 新建服务端并且指定端口号
try {
mServerSocket = new ServerSocket(11111);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while (true) {
try {
// 将服务端接收到的客户端Socket传给socket,用来与该客户端进行通信
socket = mServerSocket.accept();
// 将连接的socket传给ChatSocket(ChatSocket实现对客户端的数据发送与接收)
ChatSocket mChatSocket = new ChatSocket(socket);
// 将ChatSocket放入ChatManager中进行管理,传入ChatManager的Vector泛型数组中
ChatManager.getChatManager().add_ChatManager(mChatSocket);
mChatSocket.start();
System.out.println("连接成功");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
然后是ChatSocket类,也是继承Thread类,用来接收客户端发送给服务器的消息,并且发送消息给其他客户端。
package socket.server;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ChatSocket extends Thread {
private Socket mSocket;// 服务器Socket既是操作客户端的object
public ChatSocket(Socket socket) {
this.mSocket = socket;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
// 获取客户端发送来的消息
InputStreamReader mInputStreamReader = new InputStreamReader(
mSocket.getInputStream(),"utf-8");
BufferedReader bfr = new BufferedReader(mInputStreamReader);
String text = null;
while ((text = bfr.readLine()) != null) {
// 向已连接的所有的客户端发送消息
// ChatManager.getChatManager().pulish(this, text);
System.out.println(text);
}
bfr.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
// 用来给客户端发送消息的方法
public void out(String out_string) {
OutputStreamWriter mOutputStreamWriter;
try {
mOutputStreamWriter = new OutputStreamWriter(
mSocket.getOutputStream());
BufferedWriter mBufferedWriter = new BufferedWriter(
mOutputStreamWriter);
mBufferedWriter.write(out_string);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
因为服务器要给多个客户端发送消息,所以需要新建一个ChatManager类,用来管理连接到服务器的客户端,将连接到服务器的客户端Socket传入Vector泛型数组。ChatManger类不需要继承Thread类,这里它起到一个管理工具的作用。
package socket.server;
import java.util.Vector;
public class ChatManager {
// 将ChatManager单例化
private ChatManager() {
// 此方法将使得其他类中不能对ChatManager实例化
}
private static final ChatManager M_CHAT_MANAGER = new ChatManager();// 保证ChatManager只有一个实例
// 一般工具类都使用static属性
public static ChatManager getChatManager() {
// 提供给其他类使用ChatManager
return M_CHAT_MANAGER;
}
// 存储ChatSocket的泛型数组
Vector<ChatSocket> vector_ChatSockets = new Vector<>();
// 当有新的客户端连接时,添加进vector
public void add_ChatManager(ChatSocket chatSocket) {
vector_ChatSockets.add(chatSocket);
}
// 收集某个客户端(cs)的信息,并发送给更多的客户端
public void pulish(ChatSocket cs, String out) {
for (int i = 0; i < vector_ChatSockets.size(); i++) {// 遍历ChatSocket
// 获取遍历的ChatSocket在Vector中的下标
ChatSocket csChatSocket = vector_ChatSockets.get(i);
// 判断遍历的ChatSocket是否为发送信息到服务器的客户端
if (!cs.equals(csChatSocket)) {
csChatSocket.out(out);
}
}
}
}
总结:
Socket通信其实就是操作Socket对象本身,服务器的ServerSocket也是起到一个转接的作用(把监听到的的客户端Socket传给服务器本身的Socket),然后Socket就相当一个中转站,去操控输入输出流,和其他的一些方法。