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);
}
}
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();
}
}
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);
}
}
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);
}
}
}
}
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();
}
}
} }