java模拟一个简单的QQ

v 项目源码

  https://github.com/hjzgg/java_QQ

v 标题效果

 

 

      

package testFour;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.BindException;
import java.net.ServerSocket;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;

public class QQ {
    public static final int PICUTER = 1; 
    public static final int FILE = 2; 
    public static final int PARAGRAPH = 3; 
    public static final int SEND = 1; 
    public static final int RECEIVE = 2; 
    public static final int FILEX = 3;
    
    public static int getUnusedPort() throws BindException{
        int port;
        for(port = 10000 ; port <= 65535; ++port){
            ServerSocket ss = null; 
            try {
                ss = new ServerSocket(port);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(ss != null) break;
        }
        if(port > 65535)
            throw new BindException("没有可用的端口!");
        return port;
    }
    
    public synchronized static void setTextPane(JTextPane tp, byte[] bt, int len, int flag, int tag){
         ImageIcon myIcon = null;
         if(tag == SEND)
             myIcon = new ImageIcon("ff.jpg");
         else if(tag == RECEIVE)
             myIcon = new ImageIcon("gg.jpg");
         else if(tag == FILEX)
             myIcon = new ImageIcon("kk.jpg");
         
         SimpleAttributeSet set = new SimpleAttributeSet();
         Document doc = tp.getStyledDocument();
         
         if(tag == SEND || tag == RECEIVE){
              tp.setCaretPosition(doc.getLength());
              JLabel fileLabel = new JLabel("", myIcon, JLabel.CENTER);
              tp.insertComponent(fileLabel);
         }
         
         if(flag == PARAGRAPH){
             FontMetrics fm = tp.getFontMetrics(tp.getFont());
             int paneWidth = tp.getWidth();
             String text = new String(bt, 0, len);
             
             if( tag/3 == SEND ){
                 StyleConstants.setForeground(set, new Color(0,255,0));//设置文字颜色
                 StyleConstants.setFontSize(set, 15);//设置字体大小
             }
             else if( tag/3 == RECEIVE){
                 StyleConstants.setForeground(set, new Color(0,0,0));//设置文字颜色
                 StyleConstants.setFontSize(set, 15);//设置字体大小
             }
             
             try
              {
                  for(int i = 0, cnt = 0; i < text.length(); ++i){
                      if((cnt += fm.charWidth(text.charAt(i))) >= paneWidth){
                          cnt = 0;
                          doc.insertString(doc.getLength(), "\n", set);
                          continue;
                      }
                      doc.insertString(doc.getLength(), String.valueOf(text.charAt(i)), set);
                  }
                  doc.insertString(doc.getLength(), "\n", set);
                  
                  tp.setCaretPosition(doc.getLength());//最简单的设置滚动条的位置到最后输出文本的地方
                                                         //就是将JTextPane中的插入符的位置移动到文本的末端!
              }
              catch (BadLocationException e)
              {
              }
             
         } else if(flag == PICUTER) {
            
             try{
                     InputStream is = new ByteArrayInputStream(bt, 0, len);
                     ImageInputStream iis = ImageIO.createImageInputStream(is);
                     Iterator<ImageReader> itImage = ImageIO.getImageReaders(iis);
                     if(itImage.hasNext()){
                         ImageReader reader = itImage.next();
                         ImageIcon ii = new ImageIcon( bt, reader.getFormatName() );
                         tp.setCaretPosition( doc.getLength() );
                         tp.insertComponent( new PicuterPanel(ii) );
                         doc.insertString(doc.getLength(), "\n", set);
                     }
             }catch(IOException ex){
                     ex.printStackTrace();
             }catch(BadLocationException e1){
                   
             }
             
         } else if(flag == FILE) {
              try{
                  tp.setCaretPosition(doc.getLength());
                  JLabel fileLabel = new JLabel(new String(bt, 0, len), myIcon, JLabel.LEFT);
                  tp.insertComponent(fileLabel);
                  doc.insertString(doc.getLength(), "\n", set);
              }catch (BadLocationException e) {
                  e.printStackTrace();
            }
         }
    }
}

class PicuterPanel extends JPanel{
    private ImageIcon ii;
    public PicuterPanel(ImageIcon ii){
        this.ii = ii;
        setPreferredSize(new Dimension(200, 300));
        setBackground(new Color(255, 255, 255));
    }
    
    protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          g.drawImage(ii.getImage(), 0, 0, 200, 300, 0, 0, ii.getIconWidth(), ii.getIconHeight(), this);
    }
}
View Code
package testFour;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;



public class QQDialog extends Frame{
        private JPanel QQP = new JPanel();
        private JButton myFriend = new JButton("QQ好友>>");
        private JPanel funP = new JPanel();
        private JButton add = new JButton("添加好友");
        private JButton serach = new JButton("查询好友");
        private JPanel pp = new JPanel();
        private JPanel tmp = null;
        private final int QQPheight = 397;
        private JScrollPane jsp = new JScrollPane(QQP);
        private static Set<String>QQset;//IP的集合
        private static Map<String, QQFrame>QQmap;//IP到对通信窗口的映射
        private static Map<String, String>nameToIP;//姓名到IP的映射
        ImageIcon[] ii = new ImageIcon[3];
        
        public static Map<String, QQFrame> getMap(){
            return QQmap;
        }
        
        public static Set<String> getSet(){
            return QQset;
        }
        
        public static Map<String, String> getNameToIP(){
            return nameToIP;
        }
        
        public QQDialog(){
            
            QQset = new TreeSet<String>();
            QQmap = new TreeMap<String, QQFrame>();
            nameToIP = new TreeMap<String, String>();
            
            ii[0] = new ImageIcon("ff.jpg");
            ii[1] = new ImageIcon("gg.jpg");
            ii[2] = new ImageIcon("kk.jpg");
            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
            jsp.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
            jsp.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            pp.add(jsp);
            pp.setLayout(new BoxLayout(pp, BoxLayout.Y_AXIS));
            QQP.setLayout(new BoxLayout(QQP, BoxLayout.Y_AXIS));
            JPanel pmyFriend = new JPanel();
            pmyFriend.setLayout(new BorderLayout());
            pmyFriend.add(myFriend, "Center");
            pmyFriend.setPreferredSize(new Dimension(300, 20));
            add(pmyFriend);
            pp.setPreferredSize(new Dimension(300, 400));
            add(pp);
            add(funP);
            
            JLabel myself = null;
            try {
                myself = new JLabel(InetAddress.getLocalHost().getHostName() + ":" + InetAddress.getLocalHost().getHostAddress());
            } catch (UnknownHostException e) {
                e.printStackTrace();
            }
            addLabelListener(myself);
            myself.setIcon(new ImageIcon("ff.jpg"));
            
            tmp = new JPanel();
            tmp.setLayout(new FlowLayout(FlowLayout.CENTER));
            tmp.setBackground(new Color(255, 0, 255));
            tmp.setPreferredSize(new Dimension(250, 60));
            tmp.add(myself);
            QQP.add(tmp);
            funP.setLayout(new FlowLayout(FlowLayout.CENTER));
            funP.add(add);
            funP.add(serach);
            
            myFriend.addMouseListener(new MouseAdapter() {
                
                    public void mouseClicked(MouseEvent e) {//将好友面板进行收缩的效果!
                        if("QQ好友>>".equals(myFriend.getText())){
                            QQP.setVisible(false);
                            myFriend.setText("QQ好友<<");
                        }
                        else{
                            QQP.setVisible(true);
                            myFriend.setText("QQ好友>>");
                        }
                    }

            });
            
            add.addMouseListener(new MouseAdapter() {
                    public void mouseClicked(MouseEvent e) {
                        InputDialog dlg = new InputDialog();
                        if(dlg.key == InputDialog.CANCELBTN || dlg.key== 0) return;
                        Random rd = new Random();
                        int index = Math.abs(rd.nextInt()) % 3;
                        JLabel ll = new JLabel(dlg.getNameText() + ":" + dlg.getIPText(), ii[index], JLabel.LEFT);
                        QQset.add(dlg.getIPText());//将新增加的好友添加到集合中!
                        nameToIP.put(dlg.getNameText(), dlg.getIPText());
                        tmp = new JPanel();
                        tmp.setLayout(new FlowLayout(FlowLayout.CENTER));
                        tmp.setBackground(new Color(255, 0, 255));
                        
                        /*
                         *  BoxLayout布局简直是蛋疼的要命,一个面板X是BoxLayout布局,如果该面板添加一个面板Y的话
                         *  那么Y就会填充X面板!如果在添加一个面板Z, 那么Y, Z就会一起布满X面板!但是可以设置Y,Z面板
                         *  的比例! 如果X添加的是一个按钮或者标签时,还不能控制其大小.....无语了!
                         *  
                         *  下面的我的做法将标签添加到面板tmp中,然后再将tmp添加中QQP面板中!这样就可以控制标签的大小了!
                         *  再添加新的面板的时候,要设置一下之前面板的PreferredSize!保证每一个标签的距离适中!
                         *  也就是保证所有的添加的面板的高度之和 == QQP.getHeight();
                         * */
                        int cnt = QQP.getComponentCount();//显示QQ好友的个数!
                        if(cnt >= 1)
                            QQP.getComponent(cnt-1).setPreferredSize(new Dimension(250, 60));
                        int h = QQP.getHeight() - cnt*60;
                        if(h < 0) h=60;
                        tmp.setPreferredSize(new Dimension(250, h));
                        tmp.add(ll);
                        QQP.add(tmp);
                        QQP.add(tmp);
                        addLabelListener(ll);//给标签添加监听器
                        JScrollBar jsb = jsp.getVerticalScrollBar();
                        QQP.updateUI();//利用当前外观的值重置 UI 属性。 也可以保证滚动条随时的更新
                        //终于搞好了,将垂直滚动条自动的移动到最低端
                        jsp.getViewport().setViewPosition(new Point(0, jsp.getVerticalScrollBar().getMaximum()));
                    }
            });
            
            serach.addMouseListener(new MouseAdapter() {
                    public void mouseClicked(MouseEvent e) {
                          String name = JOptionPane.showInputDialog(null, "好友姓名", "好友查询", JOptionPane.OK_OPTION);
                          if(name == null)  return ;
                          
                          String ip = nameToIP.get(name);
                          
                          if(ip == null)
                                  JOptionPane.showMessageDialog(null, "好友不存在!", "查询结果", JOptionPane.OK_OPTION);
                          else{
                              QQFrame fm = QQmap.get(ip);
                              if(fm == null){
                                  try{
                                         String[] ipStr = ip.split("\\.");//将字符串中的数字分离
                                         byte[] ipBuf = new byte[4];//存储IP的byte数组
                                         for(int i = 0; i < 4; i++){
                                             ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
                                         }
                                         fm = new QQFrame(name, ipBuf);
                                    }catch(RuntimeException ex){
                                         JOptionPane.showMessageDialog(null, ex.getMessage(), "Socket错误!", JOptionPane.OK_CANCEL_OPTION);
                                         return ;
                                    }
                                  QQmap.put(ip, fm);
                              }
                              else fm.requestFocus();
                          }
                    }
            });
            
            addWindowListener(new WindowAdapter() {
                    public void windowClosing(WindowEvent e) {
                        if(qr == null) System.out.println("hehe");
                        qr.setFlag();//udp服务线程停止
                        ss.setFlag();//tcp服务线程停止
                        System.exit(0);
                    }
            });
            
            QQP.setBackground(new Color(255, 0, 255));
            funP.setBackground(new Color(255, 255, 0));
            setResizable(false);
            setSize(300, 500);
            setLocation(500, 200);
            setVisible(true);
        }
        
        
        public void addLabelListener(final JLabel lab){
             lab.setOpaque(true);
             lab.setBackground(new Color(255, 255, 255));
             lab.setPreferredSize(new Dimension(250, 55));
             
             String NameAndIP = lab.getText();
              String name = NameAndIP.substring(0, NameAndIP.indexOf(':'));
              String ip = NameAndIP.substring(NameAndIP.indexOf(':') + 1, NameAndIP.length());
            
             nameToIP.put(name, ip);
             QQset.add(ip);
             
             lab.addMouseListener(new MouseAdapter() {
                     Color oldC = lab.getBackground();
                     public void mouseEntered(MouseEvent e) {
                          lab.setBackground(new Color(0, 255, 0));
                     }
                     
                     public void mouseExited(MouseEvent e) {
                          lab.setBackground(oldC);
                     }
                     
                     public void mouseClicked(MouseEvent e) {
                          //打开通信窗口
                          if(e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2){
                                 String NameAndIP = lab.getText();
                                 String name = NameAndIP.substring(0, NameAndIP.indexOf(':'));
                                 if(QQmap.get(nameToIP.get(name)) != null){//这个好友的窗口已经存在!
                                    QQmap.get(nameToIP.get(name)).requestFocus();
                                    return ;
                                 }
                                 QQFrame fm = null;
                                try{
                                     String[] ipStr = nameToIP.get(name).split("\\.");//将字符串中的数字分离
                                     byte[] ipBuf = new byte[4];//存储IP的byte数组
                                     for(int i = 0; i < 4; i++){
                                         ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
                                     }
                                     fm = new QQFrame(name, ipBuf);
                                     QQmap.put(nameToIP.get(name), fm);//name 和 窗口的映射!
                                }catch(RuntimeException ex){
                                    JOptionPane.showMessageDialog(null, ex.getMessage(), "错误提示!", JOptionPane.OK_CANCEL_OPTION);
                                    return ;
                                }
                          }
                          else if(e.getButton() == MouseEvent.BUTTON3){
                               JPopupMenu pm = new JPopupMenu("胡峻峥");
                               JMenuItem del = new JMenuItem("删除");
                               del.setFont(new Font("华文行楷", Font.ITALIC, 20));
                               del.setForeground(new Color(255, 0, 0));
                               del.addActionListener(new ActionListener() {
                                    public void actionPerformed(ActionEvent e) {
                                        int choose = JOptionPane.showConfirmDialog(null, "确定删除!", "删除对话框", JOptionPane.YES_NO_OPTION);
                                           if(choose == JOptionPane.OK_OPTION){
                                               QQP.remove(lab.getParent());
                                               int cnt = QQP.getComponentCount();
                                               int h = QQP.getHeight() - (cnt-1)*60;
                                             if(h < 0) h=60;
                                               if(cnt >= 1)
                                                 QQP.getComponent(cnt-1).setPreferredSize(new Dimension(250, h));
                                               
                                               cnt = QQP.getComponentCount();
                                               if(cnt*60 <= QQPheight)
                                                   QQP.setPreferredSize(new Dimension(QQP.getWidth(), QQPheight));
                                               else 
                                                   QQP.setPreferredSize(new Dimension(QQP.getWidth(), cnt*60));
                                               QQP.updateUI();
                                               
                                               String NameAndIP = lab.getText();
                                              String ip = NameAndIP.substring(NameAndIP.indexOf(':') + 1);
                                               QQset.remove(ip);
                                               QQFrame fm = QQmap.get(ip);
                                               if(fm != null) fm.dispose();
                                               nameToIP.remove(NameAndIP.substring(0, NameAndIP.indexOf(':')));
                                               QQmap.remove(ip);
                                           }
                                    }
                              });
                               
                               JMenuItem edit = new JMenuItem("编辑");
                               edit.addActionListener(new ActionListener() {
                                
                                  public void actionPerformed(ActionEvent e) {
                                        //得到之前的数据!
                                        String content = lab.getText();
                                        String oldName = content.substring(0, content.indexOf(':'));
                                        String oldIP = content.substring(content.indexOf(':')+1);
                                        //从新设置到文本框中
                                        InputDialog id = new InputDialog(oldIP, oldName, true);
                                        if(id.key == InputDialog.CANCELBTN || id.key== 0) return;
                                        lab.setText(id.NAME + ":" + id.IP);
                                        
                                        QQFrame fm = QQmap.get(oldIP);
                                        if(fm != null){
                                            try{
                                                fm.setSendIAD(id.IP);
                                                
                                                QQmap.put(id.IP, fm);
                                                fm.setTitle(id.NAME);
                                                QQmap.remove(oldIP);
                                                QQset.remove(oldIP);
                                                QQset.add(id.IP);
                                                nameToIP.remove(oldName);
                                                nameToIP.put(id.NAME, id.IP);
                                                
                                            }catch(RuntimeException ex){
                                                JOptionPane.showMessageDialog(null, ex.getMessage(), "修改之后的IP!", JOptionPane.OK_OPTION);
                                            }
                                        }
                                    }
                              });
                               edit.setFont(new Font("华文行楷", Font.ITALIC, 20));
                               edit.setForeground(new Color(255, 0, 255));
                               pm.setBorderPainted(true);
                               pm.setBackground(new Color(125, 0, 125));
                               pm.add(del);  pm.add(edit);
                               pm.show(lab, e.getX(), e.getY());
                          }
                     }
                     
             });
        }
        
        //内部类,用来访问Frame中的数据成员
        class InputDialog extends Dialog{
            private JLabel ipLabel = new JLabel("IP地址:");
            private JLabel nameLabel = new JLabel("姓名:");
            private JButton okBtn = new JButton("确定");
            private JButton cleBtn = new JButton("取消");
            private JTextField ipText = new JTextField(20);
            private JTextField nameText = new JTextField(20);
            private static final int OKBTN = 1;
            private static final int CANCELBTN = 2;
            private int key = 0;
            private String IP = null, NAME = null; 
            private boolean flag = false;
            void initDialog(){
                JPanel p = null;
                setModal(true);
                setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
                
                add(p = new JPanel());
                p.setLayout(new FlowLayout(FlowLayout.CENTER));
                ipLabel.setPreferredSize(new Dimension(50, 12));
                p.add(ipLabel); p.add(ipText);
                
                
                add(p = new JPanel());
                p.setLayout(new FlowLayout(FlowLayout.CENTER));
                nameLabel.setPreferredSize(new Dimension(50, 12));
                p.add(nameLabel); p.add(nameText);
                
                add(p = new JPanel());
                p.setLayout(new FlowLayout(FlowLayout.CENTER));
                p.add(okBtn); p.add(cleBtn);
                
                addWindowListener(new WindowAdapter() {
                        public void windowClosing(WindowEvent e) {
                             key = 0;
                             dispose();
                        }
                });
                
                addMouseListener(new MouseAdapter() {
                        public void mouseClicked(MouseEvent e) {
                             requestFocus();
                        }
                });
                
                okBtn.addMouseListener(new MouseAdapter() {
                        public void mouseClicked(MouseEvent e) {
                             key = InputDialog.OKBTN;
                             if("".equals(ipText.getText()) || "".equals(nameText.getText()) || !checkIP(ipText.getText()) )
                                     JOptionPane.showMessageDialog(null, "信息不全或者IP填写错误!");
                             else{
                                 String ip = ipText.getText();
                                 if(!flag && QQset.contains(ip)){
                                     JOptionPane.showMessageDialog(null, "好友已存在!", "QQ好友", JOptionPane.OK_OPTION);
                                     return ;
                                 }
                                 IP = ipText.getText();
                                 NAME = nameText.getText();
                                 dispose();
                             }
                        }
                });
                
                cleBtn.addMouseListener(new MouseAdapter() {
                        public void mouseClicked(MouseEvent e) {
                            key = InputDialog.CANCELBTN;
                            dispose();
                        }
                });
                setSize(300, 200);
                setLocation(200, 200);
                setVisible(true);
            }
            
            public InputDialog(String ip, String name){
                super(new Frame());
                ipText.setText(ip);
                nameText.setText(name);
                initDialog();
            }
            
            public InputDialog(String ip, String name, boolean flag){
                super(new Frame());
                ipText.setText(ip);
                nameText.setText(name);
                this.flag = flag;
                initDialog();
            }
            
            public InputDialog(){
                super(new Frame());
                initDialog();
            }
            
            public boolean checkIP(String ip){
                int i, begin = 0, end;
                for(i = 1; i <= 4; ++i){
                    end = ip.indexOf('.', begin);
                    if(end == -1) return false;
                    int p = Integer.valueOf(ip.substring(begin, end));
                    if(p < 0 || p > 255)  return false;
                }
                return true;
            }
            
            public String getIPText(){
                return IP;
            }
            
            public String getNameText(){
                return NAME;
            }
            
        }
        
        
        private static ServerSocketQQ ss = null;
        private static QQReceive qr = null;
        
        public static void main(String[] args){

             ss = new ServerSocketQQ();
             new Thread(ss).start();
             if(ServerSocketQQ.getPort() < 1) return;
             
             qr = new QQReceive();
             new Thread(qr).start();
             if(QQReceive.getPort() < 1)  return ;
             
            new QQDialog();
        }
}
View Code
package testFour;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextPane;
import javax.swing.filechooser.FileFilter;



public class QQFrame extends Frame{
     private TextArea taSend = new TextArea();
     private JTextPane taReceive = new JTextPane();
     private JScrollPane p = new JScrollPane(taReceive);
     private JPanel pSend = new JPanel();
     private JPanel pReceive = new JPanel();
     private Label laSend = new Label("发送端.....");
     private Label laReceive = new Label("接收端.....");
     private JButton FileBtn = new JButton("传输文件");
     private JButton PicuterBtn = new JButton("发送图片");
     private InetAddress sendIAD = null;//当前窗口所对应的好友所在机器的IP对象
     private String QQname = null;//该对话框所对应的好友的姓名
     private Socket st =null;
     private String text;
     private DatagramSocket ds = null;
    
     public QQFrame(String name, byte[] ipBuf) throws RuntimeException{
         try {
            sendIAD = InetAddress.getByAddress(ipBuf);
         } catch (UnknownHostException e3) {
            throw new RuntimeException("IP错误(不存在或无发链接)!");
         }
         
         ds = QQReceive.getUdpSocket();
         if(ds == null)  throw new RuntimeException("udp Socket出错!");
         
         QQname = name;
         text = "";
         setSize(600, 600);
         setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
         pSend.setLayout(new FlowLayout(FlowLayout.LEFT));
         pSend.add(laSend);
         pSend.add(FileBtn);
         pSend.add(PicuterBtn);
         pReceive.setLayout(new FlowLayout(FlowLayout.LEFT));
         pReceive.add(laReceive);
         
         taReceive.setForeground(new Color(255, 0, 255));
         add(pReceive);
         add(p);
         add(pSend);
         add(taSend);
         setTitle("我的好友 " + QQname);
         
         
         taSend.setPreferredSize(new Dimension(0, 200));
         taReceive.setPreferredSize(new Dimension(0, 400));
         
         taSend.setFont(new Font("仿宋", Font.PLAIN, 20));
         taReceive.setFont(new Font("黑体", Font.PLAIN, 25));
         
         taReceive.setEditable(false);//不能进行文本的编辑,但是可以进行访问
         
         taSend.addKeyListener(new KeyAdapter() {
            
             public void keyPressed(KeyEvent e) {
                if(e.getKeyCode() == KeyEvent.VK_ENTER){
                     text = taSend.getText();
                     if(text == null) return;
                     text += "\n\n";
                     byte[] bt = text.getBytes();
                     DatagramPacket dp = null;
                     try {
                         //向指定的ip和端口发送数据~!
                         //先说明一下数据是谁发送过来的!
                         byte[] ip = InetAddress.getLocalHost().getHostAddress().getBytes();
                         dp = new DatagramPacket(ip, ip.length, sendIAD, QQReceive.getPort());
                         ds.send(dp);
                         
                         //这里主要是因为多可数据报包发送时会产生丢包的情况...所以暂停一段时间!
                         try {
                            Thread.sleep(100);
                         } catch (InterruptedException e1) {
                         }
                         
                         dp = new DatagramPacket("PARAGRAPH".getBytes(), "PARAGRAPH".getBytes().length, sendIAD, QQReceive.getPort());
                         ds.send(dp);
                         
                         try {
                                Thread.sleep(100);
                         } catch (InterruptedException e1) {
                             
                         }
                         
                         dp = new DatagramPacket(bt, bt.length, sendIAD, QQReceive.getPort());
                         ds.send(dp);
                     } catch (IOException e1) {
                        e1.printStackTrace();
                     }
                     
                     synchronized(QQ.class){//发送端向接收窗口添加数据时 要 和 接收端向接收窗口添加数据时同步!
                         byte[] x = null;
                         try {
                            x = new String(InetAddress.getLocalHost().getHostName() + " : ").getBytes();
                         } catch (UnknownHostException e1) {
                            e1.printStackTrace();
                         }
                         QQ.setTextPane(taReceive, x, x.length, QQ.PARAGRAPH, QQ.SEND);
                         x = text.getBytes();
                         QQ.setTextPane(taReceive, x, x.length, QQ.PARAGRAPH, QQ.SEND*3);
                         taSend.requestFocus();
                     }
                     
                     taSend.setText("");//发送端清空
                     e.consume();//不让这个回车字符在输入端显示!
                     return ;
                }
            }
             
         });
         
         addWindowListener(new WindowAdapter() {

            public void windowClosing(WindowEvent e) {
                Map<String, QQFrame>mp = QQDialog.getMap();
                mp.remove(sendIAD.getHostAddress());
                dispose();
            }
             
         });
         
         FileBtn.addMouseListener(new MouseAdapter() {//文件传输
                public void mouseClicked(MouseEvent e) {
                     JFileChooser jfc = new JFileChooser();
                     jfc.showOpenDialog(null);
                     File fl = jfc.getSelectedFile();
                     if(fl == null) return ;
                     try {
                        st =  new Socket();//尝试连接对方
                        st.connect(new InetSocketAddress(sendIAD, ServerSocketQQ.getPort()), 1000);
                     } catch (IOException e2) {
                        st = null;
                        JOptionPane.showMessageDialog(null, "请求超时或连接错误!", "ServerSocket", JOptionPane.OK_CANCEL_OPTION);
                     }
                     if(st != null){
                        try {
                            byte[] bt = new byte[1024];
                            InputStream is = st.getInputStream(); 
                            OutputStream os = st.getOutputStream();
                            //先说明一下是谁发送过来的!
                            byte[] ip = InetAddress.getLocalHost().getHostAddress().getBytes();
                            os.write(ip);
                            os.flush();
                            
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                             
                            }
                            
                            //向对方首先发送文件名, 然后发送文件内容!
                            os.write(fl.getName().getBytes());
                            os.flush();
                            
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e1) {
                             
                            }
                            
                            int len;
                            InputStream fis = new FileInputStream(fl);
                            while( (len = fis.read(bt)) != -1){
                                os.write(bt, 0, len);
                                os.flush();
                            }
                            bt = new String(Calendar.getInstance().getTime().toString() + ":文件已传输!").getBytes();
                            QQ.setTextPane(taReceive, bt, bt.length, QQ.FILE, QQ.FILEX);
                            st.shutdownOutput();//输出流结束,并标记一下,使服务端知道客户端输出已经结束了!
                            st.close();
                        
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                     }
                }
         });
         
         PicuterBtn.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    JFileChooser jfc = new JFileChooser();
                    jfc.setFileFilter(new PicuterFilter());//设置当前的文件过滤器!
                    jfc.setAcceptAllFileFilterUsed(false);//设置所有文件过滤器不使用!
                    //jfc.addChoosableFileFilter(new Filter());
                    jfc.showOpenDialog(null);
                    
                   //将输入流按照下面方式处理, 根据Iterator<ImageReader> itImage是否能
                   //成功的返回一个ImageReader对象确认该流文件是否是一个图片文件!
                   //并ImageReader类中的getFormatName()得到文件的格式!
                   //通过最后可以通过ImageIcon的byte[]构造函数建立ImageIcon对象!
                   //最后将图片显示在面板上!
                    File fl = jfc.getSelectedFile();
                    if(fl == null) return ;
                    try{
                             InputStream is = new FileInputStream(fl);
                             ImageInputStream iis = ImageIO.createImageInputStream(is);
                             Iterator<ImageReader> itImage = ImageIO.getImageReaders(iis);
                             if(itImage.hasNext()){
                                  ImageReader reader = itImage.next();
                                  byte[] imageByte = new byte[1024*64];
                                  int len = iis.read(imageByte);
                                  if(len > 64 * 1000){
                                      JOptionPane.showMessageDialog(new Frame(), "图片过大!请采用文件传输!");
                                      return ;
                                  }
                                  DatagramPacket dp = null;
                                  //先说明一下数据是谁发送过来的!
                                  byte[] ip = InetAddress.getLocalHost().getHostAddress().getBytes();
                                  dp = new DatagramPacket(ip, ip.length, sendIAD, QQReceive.getPort());
                                  ds.send(dp);
                                  
                                  try {
                                        Thread.sleep(100);
                                  } catch (InterruptedException e1) {
                                  }
                                  
                                  dp = new DatagramPacket("PICUTER".getBytes(), "PICUTER".getBytes().length, sendIAD, QQReceive.getPort());
                                  ds.send(dp);
                                  
                                  try {
                                        Thread.sleep(100);
                                  } catch (InterruptedException e1) {
                                  }
                                  
                                  dp = new DatagramPacket(imageByte, len, sendIAD, QQReceive.getPort());
                                  ds.send(dp);
                                  synchronized(QQ.class){
                                      byte[] name = null;
                                      name = new String(InetAddress.getLocalHost().getHostName() + " : ").getBytes();
                                      QQ.setTextPane(taReceive, name, name.length, QQ.PARAGRAPH, QQ.SEND);
                                      QQ.setTextPane(taReceive, imageByte, len, QQ.PICUTER, 0);
                                  }
                             }
                             else throw new NoPicuterException("不是一张图片!");
                    }catch(IOException ex){
                        ex.printStackTrace();
                    }
                }
         });
         
         setVisible(true);
     }
     
     public void setSendIAD(String ip) throws RuntimeException{
         String[] ipStr = ip.split("\\.");//将字符串中的数字分离
         byte[] ipBuf = new byte[4];//存储IP的byte数组
         for(int i = 0; i < 4; i++){
             ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
         }
         try {
             sendIAD = InetAddress.getByAddress(ipBuf);
          } catch (UnknownHostException e3) {
             throw new RuntimeException("IP错误(不存在或无发链接)!");
          }
     }
     
     public DatagramSocket getDs(){
         return ds;
     }
     
     public JTextPane getReceive(){
         return taReceive;
     }
     
}

class PicuterFilter extends FileFilter {
     
    public boolean accept(File file){
           return(file.isDirectory() || file.getName().endsWith(".gif") 
                  || file.getName().endsWith(".png") || file.getName().endsWith(".bmp")
                  || file.getName().endsWith(".jpg") );
           /* 返回要显示的文件类型 */
           /*
            *   File.isDirectory()测试此抽象路径名表示的文件是否是一个目录
           */
      }
      
      public String getDescription() {
          return("Picuter Files(*.gif, *.png, *.jpg, *.bmp)");                  //返回显示文件类型的描述
      }
}

class NoPicuterException extends IOException{
    public NoPicuterException(String x){
        super(x);
    }
}
View Code
package testFour;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Map;
import java.util.Set;

import javax.swing.JOptionPane;

public class QQReceive implements Runnable{
    private QQFrame fm = null;
    private static DatagramSocket ds = null;
    private static int port = 10101;
    private boolean flag = true;
    
    public void setFlag(){
        if(ds != null)
            ds.close();
        flag = false;
    }
    public QQReceive(){
        try {
            //建立udp通信方式
            ds = new DatagramSocket(port);
         } catch (SocketException e1) {
             port = -1;
             JOptionPane.showMessageDialog(null, "DatagramSocket端口绑定错误!", "绑定错误", JOptionPane.OK_CANCEL_OPTION);
        }
    }
    
    public static DatagramSocket getUdpSocket(){
        return ds;
    } 
    
    public static int getPort(){
        return port;
    }
    
    public DatagramSocket getDS(){
        return ds;
    }
    
    public void run(){
        if(ds == null) return ;
        byte[] bt = new byte[10024*10]; 
        DatagramPacket dp = new DatagramPacket(bt, bt.length); 
        while(flag){
            int flagx = 0;
            try {
                    //ds.setReceiveBufferSize(size);
                    ds.receive(dp);
                    String ip = new String(dp.getData(), 0, dp.getLength());
                    
                    ds.receive(dp);
                    String tag = new String(dp.getData(), 0, dp.getLength());
                    
                    ds.receive(dp);
                    
                    Map<String, QQFrame>mp = QQDialog.getMap();
                    Set<String>  set = QQDialog.getSet();
                    fm = mp.get(ip);
                    System.out.println(ip);
                    if(set.contains(ip) && fm == null){//如果存在该好友,但是不存在对应的对话窗口
                         //自动产生对话窗口
                         Map<String, String> nameToIP = QQDialog.getNameToIP();
                         String[] ipStr = ip.split("\\.");//将字符串中的数字分离
                         byte[] ipBuf = new byte[4];//存储IP的byte数组
                         for(int i = 0; i < 4; i++){
                             ipBuf[i] = (byte)(Integer.parseInt(ipStr[i])&0xff);
                         }
                         String name = null;
                         for(String ss : nameToIP.keySet())
                             if( ip.equals(nameToIP.get(ss)) ){
                                   name = ss;
                                   break;
                             }
                         fm = new QQFrame(name, ipBuf);
                    }else if(fm != null){
                         fm.requestFocus();
                    }
                    
                    if( tag.equals("FILE") )
                        flagx = QQ.FILE;
                    else if( tag.equals("PICUTER"))
                        flagx = QQ.PICUTER;
                    else if( tag.equals("PARAGRAPH"))
                        flagx = QQ.PARAGRAPH;
                
            } catch (IOException e) {
                e.printStackTrace();
            }
            synchronized(QQ.class){
                if(fm == null) continue;
                byte[] x = new String(dp.getAddress().getHostName() + " : ").getBytes();
                QQ.setTextPane(fm.getReceive(), x, x.length, QQ.PARAGRAPH, QQ.RECEIVE);
                QQ.setTextPane(fm.getReceive(), dp.getData(), dp.getLength(), flagx, QQ.RECEIVE*3);
            }
        }
    }
}
View Code
package testFour;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.Map;
import java.util.Set;

import javax.swing.JOptionPane;

public class ServerSocketQQ implements Runnable{
    private ServerSocket sst = null;
    private Socket st = null;
    private static int port = 10100;
    private boolean flag = true;
    
    public void setFlag(){
        if(sst != null)
            try {
                sst.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        flag = false;
    }
    
    public static int getPort(){
        return port;
    }
    
    public ServerSocketQQ(){
        //建立服务端
        try {
            sst = new ServerSocket(port);
        } catch (IOException e) {
            port = -1;
            JOptionPane.showMessageDialog(null, "ServerSocket端口绑定错误!", "绑定错误", JOptionPane.OK_CANCEL_OPTION);
        }
        
    }
    
    public void run(){
        byte[] bt = null;
        int len = 0;
        if(sst == null)  return ;
        while(true){
            try{
                //侦听并接受到此服务套接字的连接。此方法在进行连接之前一直阻塞。 创建新套接字 
                st = sst.accept();
                //得到客户端传输过来的流
                InputStream is = st.getInputStream();
                OutputStream os  = st.getOutputStream();
                bt = new byte[1024];
                
                len = is.read(bt);
                String name = new String(bt, 0, len);
                QQFrame fm = null;
                Map<String, QQFrame>mp = QQDialog.getMap();
                Set<String>  set = QQDialog.getSet();
                fm = mp.get(name);
                if(set.contains(name) && fm == null){//如果存在该好友,但是不存在对应的对话窗口
                     //自动产生对话窗口
                     Map<String, String> nameToIP = QQDialog.getNameToIP();
                     fm = new QQFrame(name, nameToIP.get(name).getBytes());
                }
                if(fm == null){//对方不存在该好友!
                    st.close();
                    continue;
                }
                
                len = is.read(bt);
                String fileName = new String(bt, 0, len);
                
                int choose = JOptionPane.showConfirmDialog(null, "接受或不接受", "文件传输提示", JOptionPane.YES_NO_OPTION);
                if(choose == JOptionPane.NO_OPTION){
                    bt = new String(Calendar.getInstance().getTime().toString() + ":文件接受失败!").getBytes();
                    QQ.setTextPane(fm.getReceive(), bt, bt.length, QQ.FILE, QQ.FILEX);
                    st.close();
                    continue;
                }
                FileOutputStream fos = new FileOutputStream( new File(fileName) );
                while( (len = is.read(bt)) != -1 ){//先将流文件变成byte[], 然后利用套接字的输出流发送给客户端
                     fos.write(bt);
                     fos.flush();
                }
                bt = new String(Calendar.getInstance().getTime().toString() + ":文件接受成功!").getBytes();
                QQ.setTextPane(fm.getReceive(), bt, bt.length, QQ.FILE, QQ.FILEX);
                st.close();
           }catch(IOException e){
               e.printStackTrace();
           }
        }
     }
    
}
View Code

 

posted @ 2014-10-02 19:39  hjzqyx  阅读(3528)  评论(0编辑  收藏  举报