写得不是很规范,但也写挺多的注释了。一般是可以看得懂的啦。没什么特别的功能,仅仅是群聊!ps:玩玩而已。直接贴代码。。。比较适合刚学Socket编程的看。界面的代码是用Netbean直接生成的,显得很笨重!
- //====================Server.java=================================
- package cc.nothing2012.blogServlet;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.InetAddress;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.util.Vector;
- public class Server {
- private ServerSocket serverSocket;
- private Socket socket;
- private static Vector<ServerObject> vector = new Vector<ServerObject>();
- private ServerObject serverObject;
- private static Vector<String> vecIPs = new Vector<String>(); //记录所有的IP对象
- public Server() {
- try {
- serverSocket = new ServerSocket(55555);
- System.out.println("服务器已经启动!"); // 后台提示
- while (true) {
- try {
- socket = serverSocket.accept(); // 一直在等待连接
- p(socket);
- final InetAddress address = socket.getInetAddress();
- p("那个丫的连接的IP:" + address);
- p(vector.size()); // 打印连接前,登陆客户端的个数。
- serverObject = new ServerObject( socket); // 说明一个客户端连接上了, 新建对象线程。
- vector.addElement(serverObject); // 往向量里面添加一个客户端。
- p("add"+address.getHostAddress());
- vecIPs.addElement("add"+address.getHostAddress());
- serverObject.start(); // 启动一个线程
- p("客户端个数:"+vector.size()); // 打印连接后,登陆客户端的个数。
- p("IP个数:"+vecIPs.size());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- } catch (IOException e) {
- p("服务器启动失败!");
- }
- }
- public void p(Object o) {
- System.out.println(o);
- }
- public static void main(String[] args) {
- new Server();
- }
- class ServerObject extends Thread {
- private DataOutputStream out = null;
- private DataInputStream in = null;
- private Socket socket=null;
- // 每个连接过来的客户端,将初始化这样的一个对象。
- public ServerObject( Socket socket) {
- this.socket=socket;
- try {
- in = new DataInputStream(socket.getInputStream());
- out = new DataOutputStream(socket.getOutputStream());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- public void initIPs(){ //无论是增加还是减少都用此方法来更新在线用户
- String allIPs="";
- for(int i=0;i<vecIPs.size();i++){ //vecIPs至少为1,故不判空
- allIPs=allIPs.concat(vecIPs.get(i)); //把ip地址都存放在一个字符串里面
- }
- try {
- for(int i=0;i<vector.size();i++){
- Server.vector.get(i).out.writeUTF(allIPs); // 输出信息给每个客户端。
- }
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- // 启动线程时,执行
- public void run() {
- boolean flag = true; // 只是一个标志
- int m;
- //根据当前的在线用户刷新,在线的用户。每个对象只初始化一次!
- initIPs();
- while (flag) {
- try {
- String message = in.readUTF(); // 输入进来的流,简称输入流,拿到客户端的信息。
- System.out.println("IP是"+socket.getInetAddress().getHostAddress()+"的"+message); // 后台打印出来
- if (message.equals("exit")) {// 如果接收到"exit"字符串说明运行该线程的客户端断开了连接 ,则需退出该循环,退出线程
- flag = false; // 退出循环(指的是本通道关闭,该对象的进程结束)
- // try{
- // Server.vecIPs.remove(this); //从vecIPs中除去本对象的IPs, 估计会出错这儿。
- // }catch(NullPointerException ee){
- // System.out.println("果然出错");
- // ee.printStackTrace();
- // }
- String tempIP="add"+socket.getInetAddress().getHostAddress();//把此IP从ip向量表里咔嚓掉
- for(int i=0;i<vecIPs.size();i++){
- if(vecIPs.get(i).equals(tempIP)){
- vecIPs.remove(i);
- break;
- }
- }
- Server.vector.remove(this); // 当客户端关闭时,从Vector里除去本对象
- initIPs(); //重新初始化各个客户端。
- } else {
- m = Server.vector.size(); // 返回共有多少个客户端目前。
- for (int i = 0; i < m; i++) { // 给每个客户端发送同样的信息。
- Server.vector.get(i).out.writeUTF(message); // 输出信息给每个客户端。
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
- //===================MyJFrame2.java===============================
- package cc.nothing2012.blogServlet;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import java.awt.event.KeyAdapter;
- import java.awt.event.KeyEvent;
- import java.awt.event.WindowAdapter;
- import java.awt.event.WindowEvent;
- import java.io.DataInputStream;
- import java.io.DataOutputStream;
- import java.io.IOException;
- import java.net.Socket;
- import java.net.UnknownHostException;
- import java.util.Timer;
- import java.util.TimerTask;
- import java.util.Vector;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- public class MyJrame2 extends javax.swing.JFrame implements Runnable {
- public static Vector<String> vectorIP = new Vector<String>();
- public static Vector<String> vectorIPtemp = new Vector<String>();
- private Socket socket;
- private DataInputStream in;
- private DataOutputStream out;
- private boolean flag = true; // 标志 如果多个客户端则会出错。
- private boolean serverClose = false;// 标识服务器端是否关闭,true为关闭,false为没关闭
- private static final long serialVersionUID = 1L;
- public MyJrame2() {
- initComponents(); //用来初始化界面
- contorClient(); //连接服务器等操作
- // this.getRootPane().setDefaultButton(jToggleButton1);
- new Timer().schedule(new TimerTask() {
- public void run() {
- // for(int i=0;i<vectorIP.size();i++){
- // System.out.println(vectorIP.get(i));
- // }
- // System.out.println(vectorIP.size());
- jList1.setListData(vectorIP);
- }
- }, 2000, 3000);
- }
- public String getMessage() {
- if (!(jTextField2.getText()).equals("")) { // 如果写的东西不为空
- if (!(jTextField1.getText()).equals("")) { // 判断是谁写的信息
- return (jTextField1.getText() + ": " + jTextField2.getText());
- } else {
- return ("默认是骚包: " + jTextField2.getText()); // 无名氏默认是ClientX
- }
- } else { // 什么都没写
- return "";
- }
- }
- public void setMessage(String message) {
- jTextArea1.append(message + "/n"); // 添加信息并换行。
- }
- public void contorClient() {
- try {
- socket = new Socket("xxx.xx.xxx.xxx", 55555); //此处新建了一个Socket,并连接服务器
- // 。通信从此位置开始。
- jButton1.addActionListener(new ActionListener() { // “发送”按钮监听
- public void actionPerformed(ActionEvent e) { // 监听按钮的方法。
- // 必须实现的
- // 。
- try {
- if (!serverClose) { // 第一次执行时,默认是开着的。之后,如果服务器开着,
- // 即没有关闭,则发送下面内容
- String message = getMessage(); // 取得某人写的某些内容
- if (!message.equals("")) {
- out = new DataOutputStream(socket
- .getOutputStream());
- out.writeUTF(message); // 把message通过s输出去
- jTextField2.setText(""); // 此处只有发送按钮在监听,
- // 故发送之后
- // ,内容理应删掉。
- }
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- });
- this.addWindowListener(new WindowAdapter() { // 监听客户端是否关闭,如果关闭,
- // 则向服务器发送一个
- // “exit”字符串
- public void windowClosing(WindowEvent e) {
- try {
- if (serverClose) { // serverClose 的值一直都是false。
- // 此处永远不会被执行。
- } else { // 因为监听到了窗口被关闭了。
- out = new DataOutputStream(socket
- .getOutputStream());
- out.writeUTF("exit"); // 既然关闭了,就发送个信号给服务器。
- // 删除该客户端。
- }
- } catch (IOException e1) {
- e1.printStackTrace();
- }
- }
- });
- //只是实现了enter键的触发而已。
- jTextField2.addKeyListener(new KeyAdapter() {
- public void keyPressed(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.VK_ENTER) {
- try {
- if (!serverClose) { //第一次执行时,默认是开着的。之后,如果服务器开着,即没有关闭
- // ,则发送下面内容
- String message = getMessage(); // 取得某人写的某些内容
- if (!message.equals("")) {
- out = new DataOutputStream(socket
- .getOutputStream());
- out.writeUTF(message); // 把message通过s输出去
- jTextField2.setText(""); //此处只有发送按钮在监听,故发送之后
- // ,内容理应删掉。
- }
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- }
- });
- new Thread(this).start(); // 打开一个线程,即执行本类的run()函数。
- } catch (UnknownHostException e) {
- e.printStackTrace();// 打印出错信息而已,别无他意。
- } catch (IOException e) {
- serverClose = true;
- setMessage("服务器不存在或未打开!");
- }
- }
- private void initComponents() {
- jLabel1 = new javax.swing.JLabel();
- jTextField1 = new javax.swing.JTextField();
- jLabel2 = new javax.swing.JLabel();
- jScrollPane1 = new javax.swing.JScrollPane();
- jTextArea1 = new javax.swing.JTextArea();
- jTextField2 = new javax.swing.JTextField();
- jButton1 = new javax.swing.JButton();
- jScrollPane2 = new javax.swing.JScrollPane();
- jList1 = new javax.swing.JList();
- setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
- setTitle("八卦聊天器");
- setBackground(new java.awt.Color(204, 204, 255));
- jLabel1.setFont(new java.awt.Font("宋体", 0, 18)); // NOI18N
- jLabel1.setText("请输入您的昵称:");
- jTextField1.setFont(new java.awt.Font("宋体", 0, 18)); // NOI18N
- jTextField1.setForeground(new java.awt.Color(204, 204, 255));
- jLabel2.setFont(new java.awt.Font("宋体", 0, 18)); // NOI18N
- jLabel2.setText("在线用户IP:");
- jTextArea1.setColumns(20);
- jTextArea1.setRows(5);
- jScrollPane1.setViewportView(jTextArea1);
- jButton1.setFont(new java.awt.Font("宋体", 0, 18)); // NOI18N
- jButton1.setText("发送");
- jButton1.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- jButton1ActionPerformed(evt);
- }
- });
- jList1.setModel(new javax.swing.AbstractListModel() {
- private static final long serialVersionUID = 1L;
- String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
- public int getSize() { return strings.length; }
- public Object getElementAt(int i) { return strings[i]; }
- });
- jScrollPane2.setViewportView(jList1);
- javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
- getContentPane().setLayout(layout);
- layout.setHorizontalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGap(56, 56, 56)
- .addComponent(jLabel1)
- .addGap(18, 18, 18)
- .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 199, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGroup(layout.createSequentialGroup()
- .addGap(26, 26, 26)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)))
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGap(26, 26, 26)
- .addComponent(jLabel2))
- .addGroup(layout.createSequentialGroup()
- .addGap(18, 18, 18)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 73, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 152, javax.swing.GroupLayout.PREFERRED_SIZE))))
- .addContainerGap(24, Short.MAX_VALUE))
- );
- layout.setVerticalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
- .addGroup(layout.createSequentialGroup()
- .addContainerGap()
- .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
- .addGap(44, 44, 44)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
- .addGap(18, 18, 18)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
- .addComponent(jScrollPane2)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 402, Short.MAX_VALUE))
- .addGap(18, 18, 18)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jTextField2, javax.swing.GroupLayout.PREFERRED_SIZE, 63, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addGap(39, 39, 39))
- );
- pack();
- }
- private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
- }
- public void run() {
- System.out.println("My IP is"
- + socket.getInetAddress().getHostAddress());
- while (flag) {
- try {
- in = new DataInputStream(socket.getInputStream());
- if (vectorIPtemp.size() != 0) {
- vectorIPtemp.removeAllElements();
- }
- boolean isIPStr = false;
- String message = in.readUTF(); // 从服务器发过来的信息
- System.out.println("从服务器获取的信息:" + message);
- // 进行匹配看是否有ip地址
- Pattern p;
- Matcher m;
- p = Pattern
- .compile("add[0-9]{1,3}//.[0-9]{1,3}//.[0-9]{1,3}//.[0-9]{1,3}");
- m = p.matcher(message); // 将信息进行匹配。
- while (m.find()) {
- isIPStr = true; // 说明是IP字符串。
- String message2 = m.group(); // 取得类似add222.17.110.117的地址。
- // 判断是否只有发送地址而已
- // String isOnlyIP=message.substring(message2.length());
- // if(!isOnlyIP.equals("")){
- // setMessage(isOnlyIP); //输出到textArea
- // }
- // 判断vectorIP中是否已存在该IP了。
- String IP = message2.substring(3);
- vectorIPtemp.addElement(IP);
- /** 由于一下只能判断增加去掉一样的IP的情况,故舍弃 */
- // boolean isExist=false;
- // if(vectorIP!=null){
- // for(int i=0;i<vectorIP.size();i++){
- // if((vectorIP.get(i).equals(IP))){
- // //如果不一样,则继续遍历。如果一样,说明存在改变isExist的值。
- // isExist=true ;
- // break; //遍历时,存在就退出。 杯具:第一次是自己,存在。而第二个不存在了,且不判断;故出错。
- // }
- // }
- // }
- // if(isExist==false){ //不存在就添加
- // vectorIP.addElement(IP);
- // }
- vectorIP.removeAllElements();// 先清空,再重新加载。
- }
- // 如果执行了 while 里面的代码,则说明传过来的信息是做IP处理的。
- if (isIPStr == false) {
- setMessage(message);
- } else {
- vectorIP = (Vector<String>) vectorIPtemp.clone(); // 重新赋值给vectorIP
- }
- } catch (IOException e) {
- serverClose = true; // 服务器可能在有客户端存在的时候关闭,此时,客户端输入流会出错,刚执行此处
- setMessage("服务器关闭了!");
- flag = false;// 跳出循环
- }
- }
- }
- private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {
- //
- }
- private void jTextField2ActionPerformed(java.awt.event.ActionEvent evt) {
- //
- }
- public static void main(String args[]) {
- new MyJrame2().setVisible(true);
- }
- private javax.swing.JButton jButton1;
- private javax.swing.JLabel jLabel1;
- private javax.swing.JLabel jLabel2;
- private javax.swing.JList jList1;
- private javax.swing.JScrollPane jScrollPane1;
- private javax.swing.JScrollPane jScrollPane2;
- private javax.swing.JTextArea jTextArea1;
- private javax.swing.JTextField jTextField1;
- private javax.swing.JTextField jTextField2;
- }
==================
有个很明显的漏洞可以修改在线IP。不过也有个很好的解决方法,那就是在客户端先对信息进行匹配处理。
最后张图: