两个客户端通信的socket简单实现
两个客户端通信的socket简单实现
这段时间学习了socket,根据简单的服务器与客户端通信,做了一个两个客户端通过服务器来进行通信的小程序。
首先定义一个简单的消息类Message,该类只有两个属性,一个是接收消息的客户端的编号,一个是消息内容,代码如下::
import java.io.Serializable;
public class Message implements Serializable {
// 客户端编号
int id;
// 消息内容
String msg;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
接下来先创建服务器端,SocketNotifyServer类,该类创建了serverSocket对象,绑定本地的8888端口,声明静态变量sessionMap来保存所有已连接的客户端,并给每个客户端分配一个编号:
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class SocketNotifyServer {
// socket服务
ServerSocket serverSocket = null;
// 用来存放已连接的客户端的socket会话
static Map<Integer, Socket> sessionMap = new HashMap<Integer, Socket>();
public void socket() {
try {
// 创建serverSocket,绑定端口为8888
serverSocket = new ServerSocket(8888);
System.out.println("服务器开启。。。");
// 客户端编号
int i = 1;
// 实现多个客户端连接
while (true) {
Socket socket = serverSocket.accept();
System.out.println("客户端" + i + "连接成功。。。");
if (socket != null) {
// 将socket放入map,key为客户端编号
sessionMap.put(i, socket);
// 开启线程处理本次会话
Thread thread = new Thread(new NotifyHandler(socket, sessionMap));
thread.setDaemon(true);
thread.start();
i++;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
new SocketNotifyServer().socket();
}
}
接下来是消息处理类,通过重写的构造方法,得到消息发送方以及所有的已连接客户端。
通过ObjectInputStream和ObjectOutputStream来对message对象进行读写:
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
public class NotifyHandler extends Thread {
Socket socket = null;
InputStream in = null;
Map<Integer, Socket> sessionMap = null;
public NotifyHandler(Socket socket, Map<Integer, Socket> sessionMap) {
this.socket = socket;
this.sessionMap = sessionMap;
}
public void run() {
try {
in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
// 实现一次连接多次通话
while (true) {
try {
Message msg = (Message) ois.readObject();
System.out.println("消息接受对象:客户端" + msg.getId() + ",消息内容:" + msg.getMsg());
// 发送数据
try {
Socket targetSocket = sessionMap.get(msg.getId());
OutputStream out = targetSocket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(msg);
System.out.println("服务端已转发");
} catch (IOException e) {
e.printStackTrace();
}
if (socket.isClosed()) {
break;
}
} catch (IOException e) {
e.printStackTrace();
try {
socket.close();
break;
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后是客户端的代码,由于没有界面以及其他原因,在客户端这里直接是默认[客户端1]和[客户端2]进行通信,所以代码中message对象的id属性是写死的,当[客户端1]启动的时候id属性的值为2,当[客户端2]启动时,id属性为1。此处把消息接收代码放在前面,是因为while (true){input = new InputStreamReader(System.in);
这里在阻塞着等待输入,如果接收消息的代码放在这段代码下方,会导致在没有发过消息的时候,接收消息的线程不会启动,收不到别的客户端发来的消息:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
public class MsgSocketClient {
Socket socket = null;
InputStreamReader input = null;
InputStream in = null;
OutputStream out = null;
/**
* @param args
*/
public void socketStart() {
try {
socket = new Socket("127.0.0.1", 8888);
System.out.println("客户端1启动.......");
// 接受返回数据
new Thread() {
public void run() {
try {
while (true) {
in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
Message msg = (Message) ois.readObject();
System.out.println("返回数据:" + msg.getMsg());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
out = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
while (true) {
input = new InputStreamReader(System.in);
String msg = new BufferedReader(input).readLine();
Message message = new Message();
message.setId(2);
message.setMsg(msg);
oos.writeObject(message);
System.out.println("已发送");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭流和连接
try {
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MsgSocketClient().socketStart();
}
}
运行结果如下图:
注意: in = socket.getInputStream(); ObjectInputStream ois = new ObjectInputStream(in);
这里不能直接写成 ObjectInputStream ois = (ObjectInputStream)socket.getInputStream();
直接强转会报异常。
上一篇: 使用 PHPMailer 发送邮件
下一篇: 堪称奇葩的搞笑爸妈