赞
踩
服务器
服务器的socket程序有以下几个任务:
Java网络编程-Socket简介
服务器socket程序:
- package socket;
-
- import java.io.*;
- import java.net.ServerSocket;
- import java.net.Socket;
-
- public class Server {
- public static void main(String[] args) {
-
- final String QUIT = "QUIT";
- final int DEFAULT_PORT = 8888;
- ServerSocket serverSocket = null;
-
- try {
- // 绑定监听端口
- serverSocket = new ServerSocket(DEFAULT_PORT);
- System.out.println("启动服务器,监听端口"+DEFAULT_PORT);
- while(true){
- //等待客户端连接
- Socket socket = serverSocket.accept();
- System.out.println("客户端["+socket.getPort()+"]已连接");
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(socket.getInputStream()));
-
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(socket.getOutputStream()));
-
- String msg = null;
- //读取客户端发送的消息,并且进行回复
- while ((msg = reader.readLine()) != null){
- System.out.println("客户端["+socket.getPort()+"]:"+msg);
-
- //回复客户端
- writer.write("服务器:已收到-"+msg+"\n");
- writer.flush();
-
- // 查看客户端是否退出
- if(QUIT.equalsIgnoreCase(msg)){
- System.out.println("客户端["+socket.getPort()+"]已退出");
- break;
- }
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if(serverSocket != null){
- try {
- serverSocket.close();
- System.out.println("关闭serverSocket");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }

创建socket、绑定端口、监听端口
创建ServerSocket、绑定端口、监听端口其实在我们的程序中,一行语句就实现了。
serverSocket = new ServerSocket(DEFAULT_PORT);
按住CTRL,进入该构造器。
源码如下:
- public ServerSocket(int port) throws IOException {
- this(port, 50, null);
- }
进入再次调用的构造器。
源码如下:
- public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
- setImpl();
- if (port < 0 || port > 0xFFFF)
- throw new IllegalArgumentException(
- "Port value out of range: " + port);
- if (backlog < 1)
- backlog = 50;
- try {
- bind(new InetSocketAddress(bindAddr, port), backlog);
- } catch(SecurityException e) {
- close();
- throw e;
- } catch(IOException e) {
- close();
- throw e;
- }
- }

进入bind方法
。
源码如下:
- public void bind(SocketAddress endpoint, int backlog) throws IOException {
- if (isClosed())
- throw new SocketException("Socket is closed");
- if (!oldImpl && isBound())
- throw new SocketException("Already bound");
- if (endpoint == null)
- endpoint = new InetSocketAddress(0);
- if (!(endpoint instanceof InetSocketAddress))
- throw new IllegalArgumentException("Unsupported address type");
- InetSocketAddress epoint = (InetSocketAddress) endpoint;
- if (epoint.isUnresolved())
- throw new SocketException("Unresolved address");
- if (backlog < 1)
- backlog = 50;
- try {
- SecurityManager security = System.getSecurityManager();
- if (security != null)
- security.checkListen(epoint.getPort());
- getImpl().bind(epoint.getAddress(), epoint.getPort());
- getImpl().listen(backlog);
- bound = true;
- } catch(SecurityException e) {
- bound = false;
- throw e;
- } catch(IOException e) {
- bound = false;
- throw e;
- }
- }

其中有两行语句如下:
- getImpl().bind(epoint.getAddress(), epoint.getPort());
- getImpl().listen(backlog);
很清楚了吧,程序调用了ServerSocket的构造器,创建了ServerSocket。
而该构造器间接实现了绑定端口、监听端口(上面两行语句)。
阻塞,等待客户端连接
Socket socket = serverSocket.accept();
可以自己去看看源码。
有客户端连接成功后,会生成一个socket
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(socket.getInputStream()));
-
- BufferedWriter writer = new BufferedWriter(
- new OutputStreamWriter(socket.getOutputStream()));
获取向客户端读、写的字符流。
- String msg = null;
- //读取客户端发送的消息,并且进行回复
- while ((msg = reader.readLine()) != null){
- System.out.println("客户端["+socket.getPort()+"]:"+msg);
-
- //回复客户端
- writer.write("服务器:已收到-"+msg+"\n");
- writer.flush();
-
- // 查看客户端是否退出
- if(QUIT.equalsIgnoreCase(msg)){
- System.out.println("客户端["+socket.getPort()+"]已退出");
- break;
- }
- }
上面是服务器读取客户端发送的消息的代码,一行一行的读取消息,并且只有当客户端发送“quit”给服务器时,才表示此客户端要退出,并且在这个过程中其他客户端是不能与服务器进行连接的,因为服务器一直在while里面读取此客户端发送的数据,不过,这只是一个体验版,以后会一步一步进行升级的,毕竟学习也是一步一步学出来的。
关闭资源
先不用纠结关闭资源的正确姿势,这是课程中讲师关闭资源的方法,等基础比较好以后,我会自己去实践一下,再进行总结,之后也会去阅读源码,写相关博客,现在的任务就是把整个流程搞明白即可,不去纠结细节,一层一层来揭开Java网络编程的面纱。
serverSocket.close();
客户端
客户端的socket程序有以下几个任务:
客户端socket程序:
- package socket;
-
- import java.io.*;
- import java.net.Socket;
-
- public class Client {
- public static void main(String[] args){
-
- final String QUIT = "QUIT";
- final String DEFAULT_SERVER_HOST = "127.0.0.1";
- final int DEFAULT_PORT = 8888;
- Socket socket = null;
- BufferedWriter writer = null;
-
- try {
- //创建socket
- socket = new Socket(DEFAULT_SERVER_HOST , DEFAULT_PORT);
-
- //创建IO流
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(socket.getInputStream()));
-
- writer = new BufferedWriter(
- new OutputStreamWriter(socket.getOutputStream()));
-
- //等待用户输入信息
- BufferedReader consoleReader = new BufferedReader(
- new InputStreamReader(System.in));
-
- while (true){
- String input = consoleReader.readLine();
-
- //发送消息给服务器
- writer.write(input+"\n");
- writer.flush();
-
- //读取服务器返回的消息
- String msg = reader.readLine();
- System.out.println(msg);
-
- // 查看用户是否退出
- if (QUIT.equalsIgnoreCase(input)){
- break;
- }
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- if(writer != null){
- try {
- writer.close(); // 会自动flush()
- System.out.println("关闭socket");
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }

创建Socket、连接服务器
socket = new Socket(DEFAULT_SERVER_HOST , DEFAULT_PORT);
进入构造器。
源码如下:
- /**
- * Creates a stream socket and connects it to the specified port
- * number on the named host.
- * <p>
- * If the specified host is {@code null} it is the equivalent of
- * specifying the address as
- * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
- * In other words, it is equivalent to specifying an address of the
- * loopback interface. </p>
- * <p>
- * If the application has specified a server socket factory, that
- * factory's {@code createSocketImpl} method is called to create
- * the actual socket implementation. Otherwise a "plain" socket is created.
- * <p>
- * If there is a security manager, its
- * {@code checkConnect} method is called
- * with the host address and {@code port}
- * as its arguments. This could result in a SecurityException.
- *
- * @param host the host name, or {@code null} for the loopback address.
- * @param port the port number.
- *
- * @exception UnknownHostException if the IP address of
- * the host could not be determined.
- *
- * @exception IOException if an I/O error occurs when creating the socket.
- * @exception SecurityException if a security manager exists and its
- * {@code checkConnect} method doesn't allow the operation.
- * @exception IllegalArgumentException if the port parameter is outside
- * the specified range of valid port values, which is between
- * 0 and 65535, inclusive.
- * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory)
- * @see java.net.SocketImpl
- * @see java.net.SocketImplFactory#createSocketImpl()
- * @see SecurityManager#checkConnect
- */
- public Socket(String host, int port)
- throws UnknownHostException, IOException
- {
- this(host != null ? new InetSocketAddress(host, port) :
- new InetSocketAddress(InetAddress.getByName(null), port),
- (SocketAddress) null, true);
- }

先不去看细节,先看注释Creates a stream socket and connects it to the specified port number on the named host.。创建流套接字并将其连接到命名主机上的指定端口号。很显然,客户端调用Socket构造器,创建了Socket,并且连接了服务器(服务器已经运行的情况下)。
- BufferedReader reader = new BufferedReader(
- new InputStreamReader(socket.getInputStream()));
-
- writer = new BufferedWriter(
- new OutputStreamWriter(socket.getOutputStream()));
获取向服务器读、写的字符流。
- //等待用户输入信息
- BufferedReader consoleReader = new BufferedReader(
- new InputStreamReader(System.in));
等待用户输入信息,并且是控制台的输入System.in
。
- while (true){
- String input = consoleReader.readLine();
-
- //发送消息给服务器
- writer.write(input+"\n");
- writer.flush();
-
- //读取服务器返回的消息
- String msg = reader.readLine();
- System.out.println(msg);
-
- // 查看用户是否退出
- if (QUIT.equalsIgnoreCase(input)){
- break;
- }
- }

向服务器发送消息,并且接收服务器的回复,也是一行一行的读取。
关闭资源
writer.close();
到这里,我们便实现了一个简易客户端-服务器编写。
大家也自己进行测试,应该是没问题的。
如果有说错的地方,请大家不吝赐教
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。