Socket的服务器端需要在某个端口上开启服务器类型的Socket,即java.net.ServerSocket,通过它的accpet方法等待并接收客户端的请求,返回的是一个java.net.Socket对象,如果一直没有客户端的请求,那么accept方法将会一直等待。
Socket客户端根据服务器的IP地址(域名)和端口号创建一个Socket对象,连接服务器。
服务器端和客户端都持有一个Socket对象,服务器端的Socket从服务器端指向客户端,而客户端的Socket从客户端指向服务器端,就像在服务器端和客户端建立了两条单向的管道。
通过Socket类提供的getOutputStream方法获得Socket的输出流,getInputStream方法获得Socket的输入流。
实例如下:
1 package book.net.simplesocket; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.io.PrintStream; 7 import java.net.ServerSocket; 8 import java.net.Socket; 9 10 /** 11 *一个简单的Socket服务器,能接收客户端的请求,并将请求返回给客户端 12 */ 13 public class SimpleServer { 14 ServerSocket serverSkt = null;//服务器端侦听的Socket 15 Socket clinetSkt = null;//客户端 16 BufferedReader in = null;//客户端输入流 17 PrintStream out = null;//客户端输出流 18 //构造方法 19 public SimpleServer(int port){ 20 System.out.println("服务器代理正在监听,端口:" + port); 21 try { 22 serverSkt = new ServerSocket(port);//创建坚挺Socket 23 } catch (IOException e) { 24 System.out.println("监听端口" + port + "失败"); 25 } 26 try { 27 clinetSkt = serverSkt.accept();//接收连接请求 28 } catch (IOException e) { 29 System.out.println("连接失败"); 30 } 31 try { 32 in = new BufferedReader(new InputStreamReader(clinetSkt.getInputStream())); 33 out = new PrintStream(clinetSkt.getOutputStream()); 34 } catch (IOException e) { 35 e.printStackTrace(); 36 } 37 } 38 //收到客户端请求 39 public String getRequest(){ 40 String frmClt = null; 41 try { 42 frmClt = in.readLine();//从客户端的输入流中读取一行数据 43 System.out.println("Server收到请求:" + frmClt); 44 } catch (IOException e) { 45 System.out.println("无法读取端口。。。。"); 46 System.exit(0); 47 } 48 return frmClt; 49 } 50 //发送响应给客户端 51 public void sendResponse(String response){ 52 out.println(response);//往客户端输出流中写数据 53 System.out.println("Server响应请求:" + response); 54 } 55 public static void main(String[] args) { 56 SimpleServer sa = new SimpleServer(8888);//启动服务器 57 while(true){ 58 //读取客户端的输入并返回给客户端 59 sa.sendResponse(sa.getRequest()); 60 } 61 } 62 } 63 64 package book.net.simplesocket; 65 66 import java.io.BufferedReader; 67 import java.io.IOException; 68 import java.io.InputStreamReader; 69 import java.io.PrintStream; 70 import java.net.Socket; 71 72 public class SimpleClient { 73 //客户端输入/输出流 74 PrintStream out; 75 BufferedReader in; 76 //构造方法 77 public SimpleClient(String serverName,int port){ 78 //根据服务器名和端口号,连接服务器 79 try { 80 Socket clientSocket = new Socket(serverName,port); 81 out = new PrintStream(clientSocket.getOutputStream()); 82 in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); 83 } catch (Exception e) { 84 System.out.println("无法连接服务器!"); 85 } 86 } 87 //发送请求 88 public void sendRequest(String request){ 89 out.println(request); 90 System.out.println("Client发送请求:" + request); 91 } 92 public String getResponse(){ 93 String str = new String(); 94 try { 95 str = in.readLine(); 96 System.out.println("Client收到Server返回:" + str); 97 } catch (IOException e) { 98 e.printStackTrace(); 99 } 100 return str; 101 } 102 } 103 104 package book.net.simplesocket; 105 106 import java.awt.BorderLayout; 107 import java.awt.event.ActionEvent; 108 import java.awt.event.ActionListener; 109 110 import javax.swing.JButton; 111 import javax.swing.JFrame; 112 import javax.swing.JLabel; 113 import javax.swing.JPanel; 114 import javax.swing.JScrollPane; 115 import javax.swing.JTextArea; 116 import javax.swing.JTextField; 117 118 public class ClientFrame extends JFrame implements ActionListener{ 119 JButton sendButton;//“发送”按钮 120 JTextField inputField;//发送内容的输入框 121 JTextArea outputArea;//服务器返回内容的文本域 122 SimpleClient client;//客户端Socket对象 123 //在构造函数中完成图形界面的初始化 124 public ClientFrame(){ 125 JLabel label1 = new JLabel("输入:"); 126 inputField = new JTextField(20); 127 JPanel panel1 = new JPanel(); 128 panel1.add(label1); 129 panel1.add(inputField); 130 131 JLabel label2 = new JLabel("服务器返回:"); 132 outputArea = new JTextArea(6,20); 133 JScrollPane crollPane = new JScrollPane(outputArea); 134 JPanel panel2 = new JPanel(); 135 panel2.setLayout(new BorderLayout()); 136 panel2.add(label2,BorderLayout.NORTH); 137 panel2.add(crollPane,BorderLayout.CENTER); 138 139 sendButton = new JButton("发 送"); 140 sendButton.addActionListener(this); 141 142 JPanel panel = new JPanel(); 143 panel.setLayout(new BorderLayout()); 144 panel.add(panel1, BorderLayout.NORTH); 145 panel.add(sendButton,BorderLayout.CENTER); 146 panel.add(panel2, BorderLayout.PAGE_END); 147 148 setTitle("Socket客户端"); 149 this.getContentPane().add(panel); 150 this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 151 } 152 @Override 153 public void actionPerformed(ActionEvent ae) { 154 //判断事件源控价是否是“发送”按钮 155 if(ae.getSource() == sendButton){ 156 client.sendRequest(inputField.getText());//发送文本框中的文本 157 //接收服务器端回应并写入文本域 158 outputArea.append(client.getResponse() + " "); 159 } 160 } 161 public static void main(String[] args) { 162 ClientFrame frame = new ClientFrame(); 163 frame.pack(); 164 //连接服务器端 165 frame.client = new SimpleClient("127.0.0.1",8888); 166 frame.setVisible(true); 167 } 168 169 }
分析:
1.SimpleServer类
该类实现了Socket服务器端。
(1)在构造方法中创建一个ServerSocket对象,侦听指定的端口,然后调用accept方法等待并接收客户端的请求,收到连接请求后,获取Socket的输入/输出流的引用。
(2)getRequest方法从Socket的输入流中读取来自客户端的请求消息,sendResponse方法将响应消息发送到Socket的输出流,即客户端。
(3)在main方法中,新建一个SimpleServer对象,然后不断地接收客户端的请求,将收到的请求按照原样返回给客户端。
2.SimpleClient类
该类实现了Socket客户端。
(1)在构造方法中,根据服务器端的IP地址和端口号创建一个Socket对象,此时便连接到服务器端,获得Socket的输入/输出流的引用。
(2)sendRequest方法向Socket的输出流中发送请求,即向服务器端发送请求:getResponse方法从Socket的输入流中读取信息,即获取服务器端的响应消息。
3.ClientFrame类
该类实现了客户端的图形化。
在文本框中输入请求消息,单击“发送”按钮,调用SimpleClient的sendRequest方法,将文本框中的消息发送给服务器端,然后调用SimpleClient的getResponse方法获得服务器端的响应消息,并显示在文本域中。