Java:基于socket的聊天实现+文件传输

这是一个使用Java Swing和Socket技术构建的聊天应用,包含文件传输功能。提供源码下载,适合学习和参考。
摘要由CSDN通过智能技术生成

该工程是基于swing的,需要一些图片。
代码放上来,供参考。
工程源码下载地址:点击下载

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.sql.Date;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GraphicsEnvironment;
import java.awt.event.*;

import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Caret;

public class MainClass{
	private static void createAndShowGUI()
	{
		new Window();
	}
	public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
	}
}


abstract class Connect{
	Writer writer;
	
	Socket socket;
	
	Thread reader;
	
	Thread executor;
	
	String data;
	
	boolean dataAvailable = false;
	
	Object Lock;
	
	Connect(Socket s){
		socket = s;
		Lock = new Object();
		try {
			connected(s);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private void connected(Socket socket) throws IOException{
		 writer = new OutputStreamWriter(socket.getOutputStream());
		 reader = new Thread(new Runnable(){
			 	public void run(){readData(socket);}
		 });
		 executor = new Thread(new Runnable(){
			 	public void run(){while(!socket.isClosed()){execute();}}
		 });
		 reader.start();
		 executor.start();
	}
	public void send(String str) {
		 try {
			writer.write(str);
			 writer.flush();
		} catch (IOException e) {
			interrupted();
			return;
		}
		
	}
	abstract void received(String Data);
	private void readData(Socket socket){
		while(!socket.isClosed())
		{
			try {
				BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				StringBuffer sb = new StringBuffer();
				int cLen = 128;
				char cbuf[] = new char[cLen];
				int readLen = br.read(cbuf, 0, cLen);
				if(readLen!=-1)
						sb.append(cbuf, 0, readLen);
				synchronized(Lock){
					if(dataAvailable==true)
						try {
							Lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					dataAvailable = true;
					
					
					data =  sb.toString();
					Lock.notifyAll();
				}
			 } catch (IOException e) {
				try {
					socket.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				interrupted();
				return;
			}
		 }
	}
	private void execute(){
		String Data;
 		synchronized(Lock){
 			if(dataAvailable){
 				Data = data;
 				data = "";
 				dataAvailable = false;
 				Lock.notifyAll();
 				received(Data);
 			}else{
 				try {
					Lock.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
 			}
 		} 		
	}
	abstract void interrupted();
	
}

class FileConnect {
		FileInputStream fis;
		FileOutputStream fos;
		InputStream sin;
		OutputStream sout;
		String filePath;
		File file;
		Socket socket;

		long length=0;
		FileConnect(Socket s, String FilePath) throws IOException{
			sin = s.getInputStream();
			sout = s.getOutputStream();
			filePath = FilePath;	
			file = new File(filePath);
			socket = s;
		}
		
		void close() throws IOException{
			sin.close();
			sout.close();
			socket.close();
		}
		
		void send() throws IOException {
			try {
				fis = new FileInputStream(file);
				byte[] buf = new byte[1024];
				int len;
				while((len=fis.read(buf))!=-1){
					sout.write(buf);
					sout.flush();
					length+=len;
				}
			} catch (IOException e) {
				sout.close();
				fis.close();
				socket.close();
			}			
		}
		
		void receive() throws IOException {
			try {
				fos = new FileOutputStream(file);
				int len;
				byte[] buf =new byte[1024];
				while((len=sin.read(buf))!=-1	){
					fos.write(buf);
					fos.flush();
					length += len;
				}
				sin.close();
				fos.close();
				socket.close();
			} catch (IOException e) {
				sin.close();
				fos.close();
				socket.close();
			}
		}
		
		boolean isClosed(){
			if( socket.isClosed() && socket.isConnected() )
				return true;
			else 
				return false;
		}
		long getFileSize(){
			return file.length();
		}
		long getDealSize(){
			return length;
		}
	}
class Window extends JFrame implements ActionListener{
	
	JButton sure, wait;
	
	Demo demo = null;
	
	static int port = 3001;
	
	public Window(){
		this.setTitle("开始连接");
		this.setSize(200,80);
		this.setLocationRelativeTo(null);
		this.setVisible(true);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		FlowLayout flow = new FlowLayout();
		flow.setAlignment(FlowLayout.CENTER);
		this.setLayout(flow);
		sure = new JButton("发起连接");
		sure.addActionListener(this);
		this.add(sure);
		
		wait = new JButton("等待连接");
		wait.addActionListener(this);
		this.add(wait);
	}
	public void actionPerformed(ActionEvent event) {
		if(event.getSource() == sure){
			String ip;
			ip = JOptionPane.showInputDialog(null, "请输入对方IP地址","");
			if(ip == null)
				JOptionPane.showMessageDialog(null, "IP地址不能为空", "警告", JOptionPane.ERROR_MESSAGE);
			try {
				Socket socket = new Socket();
				socket.connect(new InetSocketAddress(ip,port), 3000);
				if(socket.isConnected())
					demo = new Demo(socket);
			} catch (UnknownHostException e1) {
				JOptionPane.showMessageDialog(null, "未能连接至该IP。", "错误", JOptionPane.ERROR_MESSAGE);
				return;
			} catch (IOException e1) {
				if(e1.getMessage().equals("Connection refused: connect"))
					JOptionPane.showMessageDialog(null, "对方未等待连接。", "错误", JOptionPane.ERROR_MESSAGE);
				else if(e1.getMessage().equals("connect timed out"))
					JOptionPane.showMessageDialog(null, "连接超时,IP不可达或未上线。", "错误", JOptionPane.ERROR_MESSAGE);
				return;
			}
			this.dispose();
		}
		if(event.getSource() == wait){
			sure.setEnabled(false);
			wait.setEnabled(false);
			Thread waitingThread = new Thread(new Runnable(){
				public void run(){
					waiting();
				}
			});
			waitingThread.start();
		}
	}
	void waiting(){
		try{
			ServerSocket server = new ServerSocket(port);
			demo = new Demo(server.accept());
			this.dispose();
			return;
		}catch(IOException e){
			e.printStackTrace();
		}
	}
}

class Demo extends JFrame implements ActionListener,DocumentListener, MouseListener, KeyListener{
	
	JPanel mainpanel = null;
	
	JTextArea inpane = null;
	
	JTextArea outpane = null;
	
	JLabel mainlabel = null;
	
	JToolBar toolbar = null;
	
	JPopupMenu mousemenu = null;                            //鼠标右键显示菜单栏
	
	JPopupMenu mousemenu1 = null;                            //鼠标右键显示菜单栏
	
	JPopupMenu mousemenu2 = null;
	
	JButton lenghan, fanu, zaijian, keai, poqiweixiao, ku, fadai, piezui, weixiao;
	
	JMenuItem  mousecut, mousecopy, mousepaste, mouseselectall, mouseclean, mousesearch;        //右键菜单栏的选项
	
	JMenuItem  mousecut1, mousecopy1, mousepaste1, mouseselectall1, mouseclean1, mousesearch1;        //右键菜单栏的选项
	
	JButton JTBcut, JTBcopy, JTBpaste, JTBfont, JTBfontcolor, JTBbold, JTBitalic, JTBexpression, JTBfile;    // 工具栏选项
	
	JButton send, close;
	
	JPanel fontpanel = null;
	
	JComboBox fontlist, sizelist;
	
	ToDo todo = null;                //作为一个内部类处理文件传输或者消息发送
	
	Socket socket = null;
	
	JFrame me = null;
	
	JFileChooser fileChooser = null;
	
	DataOutputStream output = null;
	
    JButton surecolor;
    
    JButton cancelcolor;
    
    Choice listfont;
    
    Choice listsize;
    
    Choice liststyle;
    
    JDialog fontdialog = new JDialog(this);
    
    JRadioButton chineselabel, englishlabel, numberlabel;
    
    JLabel examplefont;
    
    JButton surefont, cancelfont;
    
    JColorChooser jc = new JColorChooser();
    
    JDialog colordialog = new JDialog();
    
	class ToDo extends Connect
	{
		ToDo(Socket s){
			super(s);
		}
		void received(String Data)
		{
			String Command = Data.substring(0,Data.indexOf("\n"));        //作为标记,发送的是文件还是消息       
			if(Command.equals("TEXT")){
				String data = Data.substring(Data.indexOf("\n")+1);
				
				
				Calendar cal=Calendar.getInstance();
				int year=cal.get(Calendar.YEAR);//得到年
				int month=cal.get(Calendar.MONTH)+1;//得到月,因为从0开始的,所以要加1
				int day=cal.get(Calendar.DAY_OF_MONTH);//得到天
				int hour=cal.get(Calendar.HOUR);//得到小时
				int minute=cal.get(Calendar.MINUTE);//得到分钟
				int second=cal.get(Calendar.SECOND);//得到秒
				
				inpane.append(socket.getInetAddress().toString().s
Dimension ss = Toolkit.getDefaultToolkit().getScreenSize(); public ChatClient(){ super("登录聊天室"); pnlLogin = new JPanel(); this.getContentPane().add(pnlLogin); lblServer = new JLabel("服务器:"); lblPort = new JLabel("端口:"); lblName = new JLabel("用户名:"); lblPassword = new JLabel("口 令:"); tfServer = new JTextField(15); tfServer.setText("127.0.0.1"); tfPort = new JTextField(6); tfPort.setText("8000"); tfName = new JTextField(20); pwd = new JPasswordField(20); btnLogin = new JButton("登录"); btnRegister = new JButton("注册"); btnExit=new JButton("退出"); pnlLogin.setLayout(null); pnlLogin.setBackground(new Color(205,112,159)); lblServer.setBounds(40,35,50,30); tfServer.setBounds(90,35,102,25); lblPort.setBounds(195,35,35,30); tfPort.setBounds(230,35,55,25); lblName.setBounds(40,70,50,30); tfName.setBounds(90,70,195,25); lblPassword.setBounds(40,100,50,30); pwd.setBounds(90,100,195,25); btnLogin.setBounds(30,160,70,25); btnRegister.setBounds(130,160,70,25); btnExit.setBounds(230,160,70,25); pnlLogin.add(lblServer); pnlLogin.add(tfServer); pnlLogin.add(lblPort); pnlLogin.add(tfPort); pnlLogin.add(lblName); pnlLogin.add(tfName); pnlLogin.add(lblPassword); pnlLogin.add(pwd); pnlLogin.add(btnLogin); pnlLogin.add(btnRegister); pnlLogin.add(btnExit); //设置登录窗口 setResizable(false); setSize(320,260); setVisible(true); setLocation((ss.width-getWidth())/2,(ss.height-getHeight())/2); //为按钮注册监听 btnLogin.addActionListener(this); btnRegister.addActionListener(this); btnExit.addActionListener(this); addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); } //按钮监听响应 public void actionPerformed(ActionEvent ae){ Object source = ae.getSource(); if (source.equals(btnLogin)){ if (tfName.getText().equals("") || pwd.getPassword().equals("")) JOptionPane.showMessageDialog(null, "用户名或密码不能为空"); else strServerIp = tfServer.getText(); login(); } if (source.equals(btnRegister)){ strServerIp = tfServer.getText(); this.dispose(); new Register(strServerIp,8000); } if (source == btnExit) { System.exit(0); } } public void login() { User data = new User(); data.name = tfName.getText(); data.password = new String(pwd.getPassword()); try { String str = InetAddress.getLocalHost().toString(); data.ip = " "+ str.substring(str.lastIndexOf("/"), str.length()); } catch (UnknownHostException ex) { Logger.getLogger(ChatClient.class.getName()).log(Level.SEVERE, null, ex); } try{ Socket sock = new Socket(strServerIp,8000); ObjectOutputStream os = new ObjectOutputStream(sock.getOutputStream()); os.writeObject((User) data); //读来自服务器socket的登录状态 BufferedReader br = new BufferedReader(new InputStreamReader(sock.getInputStream())); String status = br.readLine(); if (status.equals("登陆成功")){ new ChatRoom((String)data.name,strServerIp); this.dispose(); //关闭流对象 os.close(); br.close(); sock.close(); } else{ JOptionPane.showMessageDialog(null, status); os.close(); br.close(); sock.close(); } } catch (ConnectException e1){ JOptionPane.showMessageDialog(null, "连接到制定服务器失败!"); } catch (InvalidClassException e2) { JOptionPane.showMessageDialog(null, "类错误!"); } catch (NotSerializableException e3) { JOptionPane.showMessageDialog(null, "对象未序列化!"); } catch (IOException e4) { JOptionPane.showMessageDialog(null, "不能写入到指定服务器!"); } } public static void main(String arg[]){ new ChatClient(); } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值