这次试验比较难,套接字这东西不好调试,很蛋疼。
首先是套接字,java的套接字封装的比较好,简单易用。
客户端这样写:
try { Socket socket = new Socket(IP_Address,Port); BufferedReader socketReader = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedWriter socketWrite = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); socketWrite.write("yourString"); socketWrite.flush(); } catch (UnknownHostException e1) { System.out .println("Error setting up socket connection: unknown host at " + IP_Address + ":" +Port); } catch (IOException e2) { System.out.println("Error setting up socket connection: " + e); }
关于这个BufferedReader的封装,
在java里inputStream,outputStream这类的东西,一般用来处理8位的流,ASCII,字符,二进制,一般用这个
Reader,Writer用来处理16位的流,就是Unicode之类的。
而且有一个,InputStreamReader,OutStreamReader 负责二者之间的转换。
其中我经常用这个 BufferedReader 和 这个 DataInputStream,后者有getInt()之类的方法比较好用。
服务端这样写
public void run() { try { server = new ServerSocket(textReceivePort); while (running) { //线程运行时在外部吧running改成false可终止线程运行 System.out.println("inThread!"); incomingConnection = server.accept(); System.out.println("HaveAccept!"); BufferedReader socketReader = new BufferedReader( new InputStreamReader( incomingConnection.getInputStream())); String t; t = socketReader.readLine(); if (t != null) chatArea.append(t + "\n"); socketReader.close(); System.out.println("message up!"); } } catch (BindException e) { System.out.println("Unable to bind to port " + textReceivePort); } catch (IOException e) { System.out .println("Unable to instantiate a ServerSocket on port: " + textReceivePort); } }
重点是不要忘记停掉不用的线程。。。。。。。。不然会出现好几十个线程在跑,占用一大堆端口的情况。
平常只要把running设成false,让线程自己跑完就可以了,
执行server.accept这一句时,线程会原地等待,这时候想终止线程,需要调用,interrupt()方法使线程抛出异常而停止。
stop()方法已经被弃用了,最好不要使用,关于为什么弃用,核心技术上有详细讲解。
布局方面,需要一个菜单栏,java提供了相关的类,很轻松就可以写好
JMenuBar menuBar = new JMenuBar();
JMenu sysMenu = new JMenu("System");
JMenuItem Item_Setting = new JMenuItem("Setting");
JMenuItem Item_Exit = new JMenuItem("Exit");
Item_Setting.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
}
});
Item_Exit.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent event) {
}
});
sysMenu.add(Item_Setting);
sysMenu.add(Item_Exit);
menuBar.add(sysMenu);
setJMenuBar(menuBar);
设置界面我直接使用了另一个JFrame,在响应里把它设成可见就可以了。
最后关闭程序时,一定要把,所有的线程和套接字都关掉。
protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { stopRun(messageRun); stopRun(fileRun); System.exit(0); } }
不过,我发现在释放掉socket之后,他所绑定的端口不会立即被释放掉,调试的时候蛋疼了一阵,谁有解决方发请留言告知。
还有,我使用BufferedWriter,和,BufferedReader,实现传输文件时会因为编码格式不同而产生乱码,比如“UTF-8”的就正常,而“”GBK“的就是乱码。
大概用Stream按bytes传就不会有问题,不过懒得写了。
最后贴上源码
import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.BindException; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; import javax.swing.JButton; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.border.TitledBorder; public class MyQQ { public static void main(String[] args) { MF = new MainFrame(); } private static class AbstractFrame extends JFrame { public AbstractFrame(String name) { super(name); } protected void setCons(int x, int y, int z, int k) { cons.gridx = x; cons.gridy = y; cons.gridwidth = z; cons.gridheight = k; } protected void init() { cons.weightx = 1; cons.weighty = 1; } protected GridBagConstraints cons = new GridBagConstraints(); } private static class MainFrame extends AbstractFrame implements ActionListener { @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source.equals(sentChat)) { try { System.out.println("inAction"); Socket socket = new Socket(IP_Address, textSendPort); BufferedReader socketReader = new BufferedReader( new InputStreamReader(socket.getInputStream())); BufferedWriter socketWrite = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); socketWrite.write(textNickName.getText() + ":" + sendArea.getText() + "\n"); socketWrite.flush(); System.out.println(messageRun.getState()); } catch (UnknownHostException e1) { System.out .println("Error setting up socket connection: unknown host at " + IP_Address + ":" + textReceivePort); } catch (IOException e2) { System.out.println("Error setting up socket connection: " + e); } } else if (source.equals(sentFile)) { JFileChooser fDialog = new JFileChooser(); fDialog.setDialogTitle("Choose File To Send"); int returnVal = fDialog.showOpenDialog(null); if (JFileChooser.APPROVE_OPTION == returnVal) { //receiveFile.setEnabled(true); try { Socket socket = new Socket(IP_Address, fileSendPort); srcFile = fDialog.getSelectedFile().getPath(); fileName = fDialog.getSelectedFile().getName(); File inFile = new File(srcFile); BufferedWriter socketWrite = new BufferedWriter( new OutputStreamWriter(socket.getOutputStream())); BufferedReader in = new BufferedReader( new InputStreamReader(new FileInputStream( inFile), "UTF-8")); System.out.println("chooesed file"); char[] tempbytes = new char[1000]; String tempbyte; fileRow = 0; while ((tempbyte = in.readLine()) != null) { fileRow++; System.out.println(tempbyte + "\n"); socketWrite.write(tempbyte + "\r"); socketWrite.flush(); } System.out.println("W_row" + fileRow); in.close(); socketWrite.close(); socket.close(); } catch (UnknownHostException e1) { System.out .println("Error setting up socket connection: unknown host at " + IP_Address + ":" + textReceivePort); } catch (IOException e2) { System.out .println("Error setting up socket connection: When send file"); } } } else if (source.equals(receiveFile)) { receiveFile.setEnabled(false); fileRun.hanging = false; } } private class MyThread extends Thread { public boolean running = true; public ServerSocket server; public Socket incomingConnection = null; boolean changePort = true; public boolean hanging = true; } private class MessageListener extends MyThread { @Override public void run() { try { server = new ServerSocket(textReceivePort); while (running) { System.out.println("inThread!"); incomingConnection = server.accept(); System.out.println("HaveAccept!"); BufferedReader socketReader = new BufferedReader( new InputStreamReader( incomingConnection.getInputStream())); String t; t = socketReader.readLine(); if (t != null) chatArea.append(t + "\n"); socketReader.close(); System.out.println("message up!"); } } catch (BindException e) { System.out.println("Unable to bind to port " + textReceivePort); } catch (IOException e) { System.out .println("Unable to instantiate a ServerSocket on port: " + textReceivePort); } } } private class FileListener extends MyThread { @Override public void run() { try { server = new ServerSocket(fileReceivePort); while (running) { System.out.println("inThreadFile!"); incomingConnection = server.accept(); System.out.println("HaveFileAccept!"); BufferedReader socketReader = new BufferedReader( new InputStreamReader( incomingConnection.getInputStream(), "UTF-8")); receiveFile.setEnabled(true); hanging = true; while (hanging) { } System.out.println("rece File~"); File outFile = new File("DownLoad"); BufferedWriter os = new BufferedWriter( new OutputStreamWriter(new FileOutputStream( outFile))); char[] tempbytes = new char[1000]; String tempbyte; while ((socketReader.readLine())!=null) { tempbyte = socketReader.readLine(); os.write(tempbyte); os.flush(); } os.close(); socketReader.close(); } } catch (BindException e) { System.out.println("FileListener Unable to bind to port " + fileReceivePort); } catch (IOException e) { System.out .println("Unable to instantiate a ServerSocket on port: " + fileReceivePort); } } } public MainFrame() { super("Main"); init(); setLayout(new GridBagLayout()); setCons(0, 0, 5, 5); add(chatArea, cons); setCons(0, 5, 1, 1); add(nickName, cons); setCons(1, 5, 4, 1); add(textNickName, cons); setCons(0, 6, 5, 3); add(sendArea, cons); setCons(0, 9, 2, 1); add(sentFile, cons); setCons(2, 9, 2, 1); add(receiveFile, cons); setCons(4, 9, 1, 1); add(sentChat, cons); setSize(300, 600); this.setVisible(true); } @Override protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) { stopRun(messageRun); stopRun(fileRun); System.exit(0); } } protected void init() { super.init(); upDate(); FlashState(); menuBar = new JMenuBar(); sysMenu = new JMenu("System"); Item_Setting = new JMenuItem("Setting"); Item_Exit = new JMenuItem("Exit"); Item_Setting.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { SF = new SettingFrame(); } }); Item_Exit.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent event) { System.out.print("bbb"); } }); sysMenu.add(Item_Setting); sysMenu.add(Item_Exit); menuBar.add(sysMenu); setJMenuBar(menuBar); chatArea.setBorder(new TitledBorder("")); sendArea.setBorder(new TitledBorder("")); receiveFile.setEnabled(false); sentFile.addActionListener(this); receiveFile.addActionListener(this); sentChat.addActionListener(this); } public void FlashState() { upDateToFile(); System.out.println("FlashState!"); stopRun(messageRun); messageRun = new MessageListener(); messageRun.start(); stopRun(fileRun); fileRun = new FileListener(); fileRun.start(); } private void upDate() { File configFile = new File("ConfigFile.txt"); if (configFile.exists()) { try { BufferedReader in = new BufferedReader(new FileReader( configFile)); textReceivePort = Integer.parseInt(in.readLine()); fileReceivePort = Integer.parseInt(in.readLine()); textSendPort = Integer.parseInt(in.readLine()); fileSendPort = Integer.parseInt(in.readLine()); IP_Address = in.readLine(); in.close(); } catch (IOException e) { } } else { upDateToFile(); } } private void upDateToFile() { File configFile = new File("ConfigFile.txt"); try { BufferedWriter out = new BufferedWriter(new FileWriter( configFile)); out.write(textReceivePort + "\r"); out.write(fileReceivePort + "\r"); out.write(textSendPort + "\r"); out.write(fileSendPort + "\r"); out.write(IP_Address + "\r"); out.close(); } catch (IOException e) { } } private void stopRun(MyThread t) { if (t != null) { t.running = false; t.changePort = false; t.hanging = false; t.interrupt(); } } private MessageListener messageRun = null; private FileListener fileRun = null; private static String srcFile; private static String fileName = "downLoad"; private static int fileRow; private JMenuBar menuBar; private JMenu sysMenu; private JMenuItem Item_Setting; private JMenuItem Item_Exit; private JTextArea chatArea = new JTextArea(10, 20); private JTextArea sendArea = new JTextArea(5, 20); private JLabel nickName = new JLabel("NickName:"); private JTextField textNickName = new JTextField(15); private JButton sentFile = new JButton("SendFile"); private JButton receiveFile = new JButton("receiveFile"); private JButton sentChat = new JButton("send"); } private static class SettingFrame extends AbstractFrame implements ActionListener { @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source.equals(submit)) { textReceivePort = Integer.parseInt(Text_1.getText()); fileReceivePort = Integer.parseInt(Text_2.getText()); String IP_Address = Text_3.getText(); textSendPort = Integer.parseInt(Text_4.getText()); fileSendPort = Integer.parseInt(Text_5.getText()); dispose(); MF.FlashState(); } else if (source.equals(cancel)) { dispose(); } } public SettingFrame() { super("Setting"); init(); setLayout(new GridBagLayout()); // ---------------------------------------- setCons(0, 0, 2, 1); add(label_1, cons); setCons(2, 0, 2, 1); add(Text_1, cons); // ---------------------------------------- setCons(0, 1, 2, 1); add(label_2, cons); setCons(2, 1, 2, 1); add(Text_2, cons); // ---------------------------------------- setCons(0, 2, 2, 1); add(label_3, cons); setCons(2, 2, 2, 1); add(Text_3, cons); // ---------------------------------------- setCons(0, 3, 2, 1); add(label_4, cons); setCons(2, 3, 2, 1); add(Text_4, cons); // ---------------------------------------- setCons(0, 4, 2, 1); add(label_5, cons); setCons(2, 4, 2, 1); add(Text_5, cons); // ---------------------------------------- setCons(1, 5, 1, 1); add(submit, cons); setCons(2, 5, 1, 1); add(cancel, cons); // ---------------------------------------- setSize(300, 300); this.setVisible(true); } protected void init() { super.init(); submit.addActionListener(this); cancel.addActionListener(this); Text_1.setText(textReceivePort + ""); Text_2.setText(fileReceivePort + ""); Text_3.setText(IP_Address); Text_4.setText(textSendPort + ""); Text_5.setText(fileSendPort + ""); } private JLabel label_1 = new JLabel("Text Receive Port:"); private JLabel label_2 = new JLabel("File Receive Port:"); private JLabel label_3 = new JLabel("Send IP:"); private JLabel label_4 = new JLabel("Text Send Port:"); private JLabel label_5 = new JLabel("File Send Port:"); private JTextField Text_1 = new JTextField(10); private JTextField Text_2 = new JTextField(10); private JTextField Text_3 = new JTextField(10); private JTextField Text_4 = new JTextField(10); private JTextField Text_5 = new JTextField(10); private JButton submit = new JButton("Submit"); private JButton cancel = new JButton("Cancel"); } private static MainFrame MF; private static SettingFrame SF; private static String IP_Address = "127.0.0.1"; private static int textReceivePort = 5555; private static int fileReceivePort = 6666; private static int textSendPort = 5555; private static int fileSendPort = 6666; }