Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上的数据的传递。在java中,有专门的socket类来处理用户的请求和响应。利用SOCKET类的方法,就可以实现两台计算机之间的通讯。这里就介绍一下在JAVA中如何利用socket进行网络编程。
所谓socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
操作java socket时用到的最多的三个方法为:
accept():主要用于服务器端产生“阻塞”,等待客户端的链接请求,并且返回一个客户端的Socket实例;
getInputStream():方法主要用来获得网络连接输入,同时返回一个InputStream对象实例;
getOutputStream():方法和上面的getInputStream相反。
一般要建立Java的Socket连接,应首先明确服务器端和客户端,服务器端使用ServerSocket监听指定的端口,使用accept等待客户端请求,链接链接,开始会话、完成会话后,关闭链接。(注意,一般socket的关闭都应该是服务器端来进行的,后面说);客户端使用Socket对网络中的某个服务器的某个端口发出链接请求,连接成功,开始会话,会话完成,Socket关闭。
一、建立服务器类
Java中有一个专门用来建立Socket服务器的类,名叫ServerSocket,可以用服务器需要使用的端口号作为参数来创建服务器对象。
- ServerSocket server = new ServerSocket(9998)
这条语句创建了一个服务器对象,这个服务器使用9998号端口。当一个客户端程序建立一个Socket连接,所连接的端口号为9998时,服务器对象server便响应这个连接,并且server.accept()方法会创建一个Socket对象。服务器端便可以利用这个Socket对象与客户进行通讯。
- Socket incoming = server.accept()
进而得到输入流和输出流,并进行封装
- BufferedReader in = new BufferedReader(new InputStreamReader(incoming.getInputStream()));
- PrintWriter out = new PrintWriter(incoming.getOutputStream(),true);
随后,就可以使用in.readLine()方法得到客户端的输入,也可以使用out.println()方法向客户端发送数据。从而可以根据程序的需要对客户端的不同请求进行回应。
在所有通讯结束以后应该关闭这两个数据流,关闭的顺序是先关闭输出流,再关闭输入流,即使用:
- out.close();
- in.close();
二、建立客户端代码
相比服务器端,客户端要简单一些,客户端只需用服务器所在机器的ip以及服务器的端口作为参数创建一个Socket对象。得到这个对象后,就可以用"建立服务器"部分介绍的方法实现数据的输入和输出。
- Socket socket = new Socket("168.160.12.42",9998);
- in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
- out = new PrintWriter(socket.getOutputStream(),true);
以上的程序代码建立了一个Socket对象,这个对象连接到ip地址为168.160.12.42的主机上、端口为9998的服务器对象。并且建立了输入流和输出流,分别对应服务器的输出和客户端的写入。
三、建立用户界面
读者可以根据自己的喜好建立自己的用户界面,这不是本文的重点。
经过以上三个步骤,就可以建立一个比较简单的对话程序。但是,为了使这个程序更加完善,应进行以下几个改进:
一、现在服务器只能服务一个客户,也就是单线程的。可以将它改进为多线程服务器。
- try
- { file://建立服务器
- ServerSocket server = new ServerSocket(9998);
- int i=1;
- for(;;)
- {
- Socket incoming = server.accept();
- new ServerThread(incoming,i).start();
- i++;
- }
- }catch (IOException ex){ ex.printStackTrace(); }
循环检测是否有客户连接到服务器上,如果有,则创建一个线程来服务这个客户,这个线程的名称是ServerThread,这个类扩展了Thread类,它的编写方法与前述的服务器的写法相同。
二、为了可以随时得到对方传送过来的消息,可以在服务器以及客户端各建立一个独立的线程来察看输入流,如果输入流中有输入,则可以即时显示出来。代码如下:
- new Thread()
- {
- public void run()
- {
- try
- {
- while(true)
- {
- checkInput();
- sleep(1000);//每1000毫秒检测一次
- }
- }catch (InterruptedException ex)
- {
- }catch(IOException ex)
- {
- }
- }
- }.start();
其中的checkInput()方法为:
- private void checkInput() throws IOException
- {
- String line;
- if((line=in.readLine())!=null) file://检测输入流中是否有新的数据
- t.setPartner(line); file://将数据流中的消息显示出来
- }
运行效果:
===============================================================
服务器端代码:
1 package com.b510.socket1706.gui.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 import java.awt.*; 6 import java.awt.event.*; 7 8 /** 9 * 服务器端程序 10 * 11 * @author Hongten 12 * 13 * @time 2012-4-29 2012 14 */ 15 public class TestServer { 16 private ServerSocket ss; 17 private Socket s; 18 private DataInputStream dis; 19 private DataOutputStream dos; 20 private TextArea ta; 21 private TextField tf; 22 23 public static void main(String args[]) { 24 TestServer ts = new TestServer(); 25 ts.createUI(); 26 ts.connect(); 27 ts.createThread(); 28 } 29 30 public void connect() { 31 try { 32 ss = new ServerSocket(8888); 33 s = ss.accept(); 34 dis = new DataInputStream(s.getInputStream()); 35 dos = new DataOutputStream(s.getOutputStream()); 36 } catch (IOException e) { 37 e.printStackTrace(); 38 // 13701303436 39 40 } 41 } 42 43 public void createUI() { 44 Frame f = new Frame("Server"); 45 ta = new TextArea(); 46 tf = new TextField(); 47 Button send = new Button("send"); 48 Panel p = new Panel(); 49 p.setLayout(new BorderLayout()); 50 p.add(tf, "Center"); 51 p.add(send, "East"); 52 f.add(ta, "Center"); 53 f.add(p, "South"); 54 MyServerListener listener = new MyServerListener(this); 55 send.addActionListener(listener); 56 tf.addActionListener(listener); 57 f.addWindowListener(new WindowAdapter() { 58 public void windowClosing(WindowEvent e) { 59 System.exit(0); 60 } 61 }); 62 f.setSize(400, 400); 63 f.setVisible(true); 64 } 65 66 public void createThread() { 67 MyServerReader reader = new MyServerReader(this); 68 reader.start(); 69 } 70 71 public void close() { 72 try { 73 dis.close(); 74 dos.close(); 75 s.close(); 76 ss.close(); 77 } catch (IOException e) { 78 e.printStackTrace(); 79 } 80 } 81 82 public DataInputStream getDataInputStream() { 83 return dis; 84 } 85 86 public DataOutputStream getDataOutputStream() { 87 return dos; 88 } 89 90 public TextArea getTextArea() { 91 return ta; 92 } 93 94 public TextField getTextField() { 95 return tf; 96 } 97 } 98 99 class MyServerListener implements ActionListener { 100 private TestServer server; 101 102 public MyServerListener(TestServer server) { 103 this.server = server; 104 } 105 106 public void actionPerformed(ActionEvent e) { 107 TextField tf = server.getTextField(); 108 String info = tf.getText(); 109 server.getTextArea().append("自己说: " + info + "\n"); 110 try { 111 server.getDataOutputStream().writeUTF(info); 112 } catch (IOException e1) { 113 e1.printStackTrace(); 114 } 115 if (info.equals("bye")) { 116 server.close(); 117 System.exit(0); 118 } 119 tf.setText(""); 120 tf.requestFocus(); 121 } 122 } 123 124 class MyServerReader extends Thread { 125 private TestServer server; 126 127 public MyServerReader(TestServer server) { 128 this.server = server; 129 } 130 131 public void run() { 132 String info; 133 DataInputStream dis = server.getDataInputStream(); 134 TextArea ta = server.getTextArea(); 135 try { 136 while (true) { 137 info = dis.readUTF(); 138 ta.append("对方说: " + info + "\n"); 139 if (info.equals("bye")) { 140 server.close(); 141 System.exit(0); 142 } 143 } 144 } catch (IOException e) { 145 e.printStackTrace(); 146 } 147 } 148 }客户端代码:
1 package com.b510.socket1706.gui.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 import java.awt.*; 6 import java.awt.event.*; 7 /** 8 * 客户端程序 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestClient { 14 private Socket s; 15 private DataInputStream dis; 16 private DataOutputStream dos; 17 private TextArea ta; 18 private TextField tf; 19 20 public static void main(String args[]) { 21 TestClient tc = new TestClient(); 22 tc.createUI(); 23 tc.connect(); 24 tc.createThread(); 25 } 26 27 public void connect() { 28 try { 29 s = new Socket("127.0.0.1", 8888); 30 dos = new DataOutputStream(s.getOutputStream()); 31 dis = new DataInputStream(s.getInputStream()); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 37 public void createUI() { 38 Frame f = new Frame("Client"); 39 ta = new TextArea(); 40 tf = new TextField(); 41 Button send = new Button("send"); 42 Panel p = new Panel(); 43 p.setLayout(new BorderLayout()); 44 p.add(tf, "Center"); 45 p.add(send, "East"); 46 f.add(ta, "Center"); 47 f.add(p, "South"); 48 MyClientListener listener = new MyClientListener(this); 49 send.addActionListener(listener); 50 tf.addActionListener(listener); 51 f.addWindowListener(new WindowAdapter() { 52 public void windowClosing(WindowEvent e) { 53 System.exit(0); 54 } 55 }); 56 f.setSize(400, 400); 57 f.setLocation(600, 0); 58 f.setVisible(true); 59 } 60 61 public void createThread() { 62 MyClientReader reader = new MyClientReader(this); 63 reader.start(); 64 } 65 66 public void close() { 67 try { 68 dis.close(); 69 dos.close(); 70 s.close(); 71 } catch (IOException e) { 72 e.printStackTrace(); 73 } 74 } 75 76 public DataInputStream getDataInputStream() { 77 return dis; 78 } 79 80 public DataOutputStream getDataOutputStream() { 81 return dos; 82 } 83 84 public TextArea getTextArea() { 85 return ta; 86 } 87 88 public TextField getTextField() { 89 return tf; 90 } 91 } 92 93 class MyClientListener implements ActionListener { 94 95 private TestClient client; 96 97 public MyClientListener(TestClient client) { 98 this.client = client; 99 } 100 101 public void actionPerformed(ActionEvent e) { 102 TextField tf = client.getTextField(); 103 String info = tf.getText(); 104 client.getTextArea().append("自己说: " + info + "\n"); 105 try { 106 client.getDataOutputStream().writeUTF(info); 107 } catch (IOException e1) { 108 e1.printStackTrace(); 109 } 110 if (info.equals("bye")) { 111 client.close(); 112 System.exit(0); 113 } 114 tf.setText(""); 115 tf.requestFocus(); 116 } 117 } 118 119 class MyClientReader extends Thread { 120 private TestClient client; 121 122 public MyClientReader(TestClient client) { 123 this.client = client; 124 } 125 126 public void run() { 127 String info; 128 DataInputStream dis = client.getDataInputStream(); 129 TextArea ta = client.getTextArea(); 130 try { 131 while (true) { 132 info = dis.readUTF(); 133 ta.append("对方说: " + info + "\n"); 134 if (info.equals("bye")) { 135 client.close(); 136 System.exit(0); 137 } 138 } 139 } catch (IOException e) { 140 e.printStackTrace(); 141 } 142 } 143 }