这几天开始学习java的网络编程,根据这个程序对socket编程进行初步了解.
程序效果图:
源代码(注释很详细):
Message类:
public class Message implements Serializable{ private String from;//sender private String to; //target private String info;//message private int type; //type
.........
}
MessageType类:
public final class MessageType { public static final int TYPE_LOGIN =0x1; public static final int TYPE_SEND =0x2; }
Server端:
public class Server { public static void main(String[] args) { //保存客户端处理的线程 Vector<UserThread> vector = new Vector<>(); ExecutorService es = Executors.newFixedThreadPool(5); //创建服务器端的Socket try { ServerSocket server = new ServerSocket(8888); System.out.println("服务器已启动,等待连接:"); while (true) { Socket socket = server.accept(); UserThread user = new UserThread(socket, vector); es.execute(user); } } catch (IOException e) { e.printStackTrace(); } } } /* 客户端处理线程 */ class UserThread implements Runnable { private String name;//客户端的用户名称 private Socket socket;//服务器连接的客户端的socket Vector<UserThread> vector;//用来传入服务器的线程池 private ObjectInputStream ois;//输入流,接收信息 private ObjectOutputStream oos;//输出流,发送信息 private boolean flag = true;//控制循环的标记 public UserThread(Socket socket, Vector<UserThread> vector) {//传入线程要使用的socket和vector this.socket = socket; this.vector = vector; vector.add(this); } @Override public void run() { //开跑 try { System.out.println("客户端" + socket.getInetAddress().getHostAddress() + "已连接");//先说明连接上的客户端 ois = new ObjectInputStream(socket.getInputStream());//装入客户端发来的信息流 oos = new ObjectOutputStream(socket.getOutputStream());//要发出去的信息流 while (flag) { //连接后开始持续接收客户端发来的信息 //读取消息对象 Message msg = (Message) ois.readObject();//读到的类型要进行强制转换 int type = msg.getType(); switch (type) { case MessageType.TYPE_SEND: String to = msg.getTo(); //遍历vector中的名字,找到线程 UserThread ut; int size = vector.size(); for (int i = 0; i < size; i++) { ut = vector.get(i); if (to.equals(ut.name) && ut != this) { ut.oos.writeObject(msg); break; } } break; case MessageType.TYPE_LOGIN: //客户端一开始连接时发来的信息会是login类型,为了提高效率,这个情况放后面 name = msg.getFrom(); //获取客户端姓名(唯一) msg.setInfo("欢迎你"); //同样使用msg,把info设置为欢迎你 oos.writeObject(msg); //接收到login信息后发送欢迎你信息给客户端 break; default: break; } } ois.close(); oos.close(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }client端:
public class Client { public static void main(String[] args) { Scanner input = new Scanner(System.in); ExecutorService es = Executors.newSingleThreadExecutor();//单线程池 try { Socket socket = new Socket("localhost", 8888); System.out.println("服务器连接成功"); ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); //先向服务器发送消息,然后在接收服务器的信息,才会收到"欢迎你" System.out.println("请输入你的名称"); String name = input.nextLine(); Message msg = new Message(name, null, null, MessageType.TYPE_LOGIN); objectOutputStream.writeObject(msg); msg = ((Message) objectInputStream.readObject()); System.out.println(msg.getInfo() + msg.getFrom()); //启动读取消息的线程 ReadInfoThread read = new ReadInfoThread(objectInputStream); es.execute(read); //使用主线程实现发送消息 boolean flag = true; while (flag) { //一直可以发消息,且这时候的type都是TYPE_SEND msg = new Message(); System.out.println("To:"); msg.setTo(input.nextLine()); msg.setType(MessageType.TYPE_SEND); msg.setFrom(name); System.out.println("info:"); msg.setInfo(input.nextLine()); objectOutputStream.writeObject(msg); } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } } //读取消息线程 class ReadInfoThread implements Runnable { private ObjectInputStream in; //服务器发来的输入流 private boolean flag = true; //是否读的标志 public void setFlag(boolean flag) { this.flag = flag; } public ReadInfoThread(ObjectInputStream in) { this.in = in; } @Override public void run() { try { while (flag) { //一直读 Message msg = ((Message) in.readObject()); //强制类型转换 //除了登录的时候,服务器把info设为"欢迎你",后面的msg info都是客户端自己构造的 System.out.println("【" + msg.getFrom() + "】对我说" + "\"" + msg.getInfo() + "\""); } if (in != null) { in.close(); } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } } }