写得不是很规范,但也写挺多的注释了。一般是可以看得懂的啦。没什么特别的功能,仅仅是群聊!ps:玩玩而已。直接贴代码。。。比较适合刚学Socket编程的看。界面的代码是用Netbean直接生成的,显得很笨重!
- //====================Server.java=================================
- packagecc.nothing2012.blogServlet;
- importjava.io.DataInputStream;
- importjava.io.DataOutputStream;
- importjava.io.IOException;
- importjava.net.InetAddress;
- importjava.net.ServerSocket;
- importjava.net.Socket;
- importjava.util.Vector;
- publicclassServer{
- privateServerSocketserverSocket;
- privateSocketsocket;
- privatestaticVector
vector= newVector(); - privateServerObjectserverObject;
- privatestaticVector
vecIPs= newVector(); //记录所有的IP对象 - publicServer(){
- try{
- serverSocket=newServerSocket(55555);
- System.out.println("服务器已经启动!");//后台提示
- while(true){
- try{
- socket=serverSocket.accept();//一直在等待连接
- p(socket);
- finalInetAddressaddress=socket.getInetAddress();
- p("那个丫的连接的IP:"+address);
- p(vector.size());//打印连接前,登陆客户端的个数。
- serverObject=newServerObject(socket);//说明一个客户端连接上了,新建对象线程。
- vector.addElement(serverObject);//往向量里面添加一个客户端。
- p("add"+address.getHostAddress());
- vecIPs.addElement("add"+address.getHostAddress());
- serverObject.start();//启动一个线程
- p("客户端个数:"+vector.size());//打印连接后,登陆客户端的个数。
- p("IP个数:"+vecIPs.size());
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- }catch(IOExceptione){
- p("服务器启动失败!");
- }
- }
- publicvoidp(Objecto){
- System.out.println(o);
- }
- publicstaticvoidmain(String[]args){
- newServer();
- }
- classServerObjectextendsThread{
- privateDataOutputStreamout=null;
- privateDataInputStreamin=null;
- privateSocketsocket=null;
- //每个连接过来的客户端,将初始化这样的一个对象。
- publicServerObject(Socketsocket){
- this.socket=socket;
- try{
- in=newDataInputStream(socket.getInputStream());
- out=newDataOutputStream(socket.getOutputStream());
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- publicvoidinitIPs(){//无论是增加还是减少都用此方法来更新在线用户
- StringallIPs="";
- for(inti=0;i
//vecIPs至少为1,故不判空 - allIPs=allIPs.concat(vecIPs.get(i));//把ip地址都存放在一个字符串里面
- }
- try{
- for(inti=0;i
- Server.vector.get(i).out.writeUTF(allIPs);//输出信息给每个客户端。
- }
- }catch(IOExceptione1){
- e1.printStackTrace();
- }
- }
- //启动线程时,执行
- publicvoidrun(){
- booleanflag=true;//只是一个标志
- intm;
- //根据当前的在线用户刷新,在线的用户。每个对象只初始化一次!
- initIPs();
- while(flag){
- try{
- Stringmessage=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(NullPointerExceptionee){
- //System.out.println("果然出错");
- //ee.printStackTrace();
- //}
- StringtempIP="add"+socket.getInetAddress().getHostAddress();//把此IP从ip向量表里咔嚓掉
- for(inti=0;i
- if(vecIPs.get(i).equals(tempIP)){
- vecIPs.remove(i);
- break;
- }
- }
- Server.vector.remove(this);//当客户端关闭时,从Vector里除去本对象
- initIPs();//重新初始化各个客户端。
- }else{
- m=Server.vector.size();//返回共有多少个客户端目前。
- for(inti=0;i
//给每个客户端发送同样的信息。 - Server.vector.get(i).out.writeUTF(message);//输出信息给每个客户端。
- }
- }
- }catch(IOExceptione){
- e.printStackTrace();
- }
- }
- }
- }
- }
- //===================MyJFrame2.java===============================
- packagecc.nothing2012.blogServlet;
- importjava.awt.event.ActionEvent;
- importjava.awt.event.ActionListener;
- importjava.awt.event.KeyAdapter;
- importjava.awt.event.KeyEvent;
- importjava.awt.event.WindowAdapter;
- importjava.awt.event.WindowEvent;
- importjava.io.DataInputStream;
- importjava.io.DataOutputStream;
- importjava.io.IOException;
- importjava.net.Socket;
- importjava.net.UnknownHostException;
- importjava.util.Timer;
- importjava.util.TimerTask;
- importjava.util.Vector;
- importjava.util.regex.Matcher;
- importjava.util.regex.Pattern;
- publicclassMyJrame2extendsjavax.swing.JFrameimplementsRunnable{
- publicstaticVector
vectorIP= newVector(); - publicstaticVector
vectorIPtemp= newVector(); - privateSocketsocket;
- privateDataInputStreamin;
- privateDataOutputStreamout;
- privatebooleanflag=true;//标志如果多个客户端则会出错。
- privatebooleanserverClose=false;//标识服务器端是否关闭,true为关闭,false为没关闭
- privatestaticfinallongserialVersionUID=1L;
- publicMyJrame2(){
- initComponents();//用来初始化界面
- contorClient();//连接服务器等操作
- //this.getRootPane().setDefaultButton(jToggleButton1);
- newTimer().schedule(newTimerTask(){
- publicvoidrun(){
- //for(inti=0;i
- //System.out.println(vectorIP.get(i));
- //}
- //System.out.println(vectorIP.size());
- jList1.setListData(vectorIP);
- }
- },2000,3000);
- }
- publicStringgetMessage(){
- if(!(jTextField2.getText()).equals("")){//如果写的东西不为空
- if(!(jTextField1.getText()).equals("")){//判断是谁写的信息
- return(jTextField1.getText()+":"+jTextField2.getText());
- }else{
- return("默认是骚包:"+jTextField2.getText());//无名氏默认是ClientX
- }
- }else{//什么都没写
- return"";
- }
- }
- publicvoidsetMessage(Stringmessage){
- jTextArea1.append(message+"/n");//添加信息并换行。
- }
- publicvoidcontorClient(){
- try{
- socket=newSocket("xxx.xx.xxx.xxx",55555);//此处新建了一个Socket,并连接服务器
- //。通信从此位置开始。
- jButton1.addActionListener(newActionListener(){//“发送”按钮监听
- publicvoidactionPerformed(ActionEvente){//监听按钮的方法。
- //必须实现的
- //。
- try{
- if(!serverClose){//第一次执行时,默认是开着的。之后,如果服务器开着,
- //即没有关闭,则发送下面内容
- Stringmessage=getMessage();//取得某人写的某些内容
- if(!message.equals("")){
- out=newDataOutputStream(socket
- .getOutputStream());
- out.writeUTF(message);//把message通过s输出去
- jTextField2.setText("");//此处只有发送按钮在监听,
- //故发送之后
- //,内容理应删掉。
- }
- }
- }catch(IOExceptionioe){
- ioe.printStackTrace();
- }
- }
- });
- this.addWindowListener(newWindowAdapter(){//监听客户端是否关闭,如果关闭,
- //则向服务器发送一个
- //“exit”字符串
- publicvoidwindowClosing(WindowEvente){
- try{
- if(serverClose){//serverClose的值一直都是false。
- //此处永远不会被执行。
- }else{//因为监听到了窗口被关闭了。
- out=newDataOutputStream(socket
- .getOutputStream());
- out.writeUTF("exit");//既然关闭了,就发送个信号给服务器。
- //删除该客户端。
- }
- }catch(IOExceptione1){
- e1.printStackTrace();
- }
- }
- });
- //只是实现了enter键的触发而已。
- jTextField2.addKeyListener(newKeyAdapter(){
- publicvoidkeyPressed(KeyEventevent){
- if(event.getKeyCode()==KeyEvent.VK_ENTER){
- try{
- if(!serverClose){//第一次执行时,默认是开着的。之后,如果服务器开着,即没有关闭
- //,则发送下面内容
- Stringmessage=getMessage();//取得某人写的某些内容
- if(!message.equals("")){
- out=newDataOutputStream(socket
- .getOutputStream());
- out.writeUTF(message);//把message通过s输出去
- jTextField2.setText("");//此处只有发送按钮在监听,故发送之后
- //,内容理应删掉。
- }
- }
- }catch(IOExceptionioe){
- ioe.printStackTrace();
- }
- }
- }
- });
- newThread(this).start();//打开一个线程,即执行本类的run()函数。
- }catch(UnknownHostExceptione){
- e.printStackTrace();//打印出错信息而已,别无他意。
- }catch(IOExceptione){
- serverClose=true;
- setMessage("服务器不存在或未打开!");
- }
- }
- privatevoidinitComponents(){
- jLabel1=newjavax.swing.JLabel();
- jTextField1=newjavax.swing.JTextField();
- jLabel2=newjavax.swing.JLabel();
- jScrollPane1=newjavax.swing.JScrollPane();
- jTextArea1=newjavax.swing.JTextArea();
- jTextField2=newjavax.swing.JTextField();
- jButton1=newjavax.swing.JButton();
- jScrollPane2=newjavax.swing.JScrollPane();
- jList1=newjavax.swing.JList();
- setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
- setTitle("八卦聊天器");
- setBackground(newjava.awt.Color(204,204,255));
- jLabel1.setFont(newjava.awt.Font("宋体",0,18));//NOI18N
- jLabel1.setText("请输入您的昵称:");
- jTextField1.setFont(newjava.awt.Font("宋体",0,18));//NOI18N
- jTextField1.setForeground(newjava.awt.Color(204,204,255));
- jLabel2.setFont(newjava.awt.Font("宋体",0,18));//NOI18N
- jLabel2.setText("在线用户IP:");
- jTextArea1.setColumns(20);
- jTextArea1.setRows(5);
- jScrollPane1.setViewportView(jTextArea1);
- jButton1.setFont(newjava.awt.Font("宋体",0,18));//NOI18N
- jButton1.setText("发送");
- jButton1.addActionListener(newjava.awt.event.ActionListener(){
- publicvoidactionPerformed(java.awt.event.ActionEventevt){
- jButton1ActionPerformed(evt);
- }
- });
- jList1.setModel(newjavax.swing.AbstractListModel(){
- privatestaticfinallongserialVersionUID=1L;
- String[]strings={"Item1","Item2","Item3","Item4","Item5"};
- publicintgetSize(){returnstrings.length;}
- publicObjectgetElementAt(inti){returnstrings[i];}
- });
- jScrollPane2.setViewportView(jList1);
- javax.swing.GroupLayoutlayout=newjavax.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();
- }
- privatevoidjButton1ActionPerformed(java.awt.event.ActionEventevt){
- }
- publicvoidrun(){
- System.out.println("MyIPis"
- +socket.getInetAddress().getHostAddress());
- while(flag){
- try{
- in=newDataInputStream(socket.getInputStream());
- if(vectorIPtemp.size()!=0){
- vectorIPtemp.removeAllElements();
- }
- booleanisIPStr=false;
- Stringmessage=in.readUTF();//从服务器发过来的信息
- System.out.println("从服务器获取的信息:"+message);
- //进行匹配看是否有ip地址
- Patternp;
- Matcherm;
- 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字符串。
- Stringmessage2=m.group();//取得类似add222.17.110.117的地址。
- //判断是否只有发送地址而已
- //StringisOnlyIP=message.substring(message2.length());
- //if(!isOnlyIP.equals("")){
- //setMessage(isOnlyIP);//输出到textArea
- //}
- //判断vectorIP中是否已存在该IP了。
- StringIP=message2.substring(3);
- vectorIPtemp.addElement(IP);
- /**由于一下只能判断增加去掉一样的IP的情况,故舍弃*/
- //booleanisExist=false;
- //if(vectorIP!=null){
- //for(inti=0;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
)vectorIPtemp.clone(); //重新赋值给vectorIP - }
- }catch(IOExceptione){
- serverClose=true;//服务器可能在有客户端存在的时候关闭,此时,客户端输入流会出错,刚执行此处
- setMessage("服务器关闭了!");
- flag=false;//跳出循环
- }
- }
- }
- privatevoidjTextField1ActionPerformed(java.awt.event.ActionEventevt){
- //
- }
- privatevoidjTextField2ActionPerformed(java.awt.event.ActionEventevt){
- //
- }
- publicstaticvoidmain(Stringargs[]){
- newMyJrame2().setVisible(true);
- }
- privatejavax.swing.JButtonjButton1;
- privatejavax.swing.JLabeljLabel1;
- privatejavax.swing.JLabeljLabel2;
- privatejavax.swing.JListjList1;
- privatejavax.swing.JScrollPanejScrollPane1;
- privatejavax.swing.JScrollPanejScrollPane2;
- privatejavax.swing.JTextAreajTextArea1;
- privatejavax.swing.JTextFieldjTextField1;
- privatejavax.swing.JTextFieldjTextField2;
- }
==================
有个很明显的漏洞可以修改在线IP。不过也有个很好的解决方法,那就是在客户端先对信息进行匹配处理。
最后张图: