Socket网络编程

  • 一、基于TCP协议的Socket编程
    • 1、Socket(套接字)简介
    • 2、Socket通信原理(*)
      • 传递字符串:
      • 传递对象:
      • 多用户同时访问服务器
    • 3、Socket类以及ServerSocket类如何使用(*)
    • 4、InetAddress类如何使用(获取IP和hostName)
  • 二、基于UDP协议的Socket编程
    • 1、DatagramSocket类如何使用
    • 2、DatagramPacket类如何使用
  • 三、总结
    • 3.1服务器编程步骤:
    • 3.2客户端编程步骤:

一、基于TCP协议的Socket编程

1、Socket(套接字)简介

Socket网络编程_第1张图片

Socket——套接字;

  • 应用程序通过“套接字”向网络发出请求或者应答网络请求
  • 最早是UNIX上的一套网络程序通讯的标准
  • 已被广泛移植到其他平台

在Internet上的主机一般运行了多个服务软件,同时提供了几种服务,每种服务都打开一个Socket并绑定到一个端口上,不同的端口对应于不同的服务进程。

Socket实质上提供了进程通信的端点,网络上的两个程序通过一个双向的通讯链路实现数据的交换,这个双向链路的一端称为一个Socket。

Socket网络编程_第2张图片

Socket分为三种类型:流式套接字、数据报式套接字,原始式套接字。

原始式套接字(Sock_RAW):该接口允许对较低层次协议,如IP直接访问,可以接收本机网卡上的数据帧或数据包,对监听网络流量和分析很有用。

流式套接字(SOCK_STREAM):提供了一个面向连接,可靠的数据传输服务,数据无差错,无重复的发生,且按发送顺序接收,内设流量控制,避免超限。(TCP协议,类似打电话,有人呼叫,有人应答)

数据报式套节奏(SOCK_DGRAM):无连接服务,数据报以独立包形式被发送,不提供无差错保证,数据可能丢失或重复,并且接收顺序无需,对应的是UDP协议。

每一种套接字被封装道路不同的类中,这些类位于java.net包中。

Java平台封装的流式套接字类:Socket类和ServerSocket类。

2、Socket通信原理(*)

客户端发送用户信息给服务端,服务端响应后的结果在返回给客户端。

首先启动服务器,然后启动客户端;

传递字符串:

LoginServer.java

/** * 服务器类 */
public class LoginServer{
    main(){

        try{
            //1.建立一个服务器Socket(ServerSocket)绑定指定端口并开始监听
            ServerSocket serverSocket = new ServerSocket(8800);
            //2.使用accept()方法阻塞等待监听,获得新的连接
            Socket socket = serverSocket.accept();
            //3.获得的输入流
            InputStream is = socket.getInputStream();
            //为了实现信息的高效读取,将字节流包装成字符流InputStreamReader,将字符流继续包装成BufferedReader,来缓冲读取字符
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //4.读取用户输入信息
            String info = null;
            while(!(info = br.readLine())!=null){
                out.print("用户信息:"+info);
            }
            //5.关闭资源
            br.close();
            is.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e){
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        }        
    }
}

LoginClient.java

/** * 客户端类 */
public class LoginClient{
    main(){
    try{
        //1.建立客户端Socket连接,指定服务器的位置及端口
        Socket socket = new Socket("localhost",8080);
        //2.得到Socket的读写流
        OutputStream os = socket.getOutputStream();
        PrintWriter pw = new PrintWriter(os);
        //输入流
        InputStream is = socket.getInputStream();
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        //3.利用流按照一定的协议对Socket进行读/写操作
        String info = "用户名:Zhangsan;密码:123456";
        pw.write(info);
        pw.flush();
        socket.shudownOutput();
        //接受服务器的响应并打印显示
        String reply = null;
        while(!(reply=br.readLine())==null){
            out.print("客户端,服务器的响应为:"+reply);
        }
        //4.关闭资源
        br.close();
        is.close();
        os.close();
        socket.close();
    }
    }

}

传递对象:

User对象类,实现接口Serializable序列化。

Socket网络编程_第3张图片

 import java.io.Serializable;
 public class User implements Serializable{

}

LoginServer.java

/** * 服务器类 */
public class LoginServer{
    main(){

        try{
            //1.建立一个服务器Socket(ServerSocket)绑定指定端口并开始监听
            ServerSocket serverSocket = new ServerSocket(8800);
            //2.使用accept()方法阻塞等待监听,获得新的连接
            Socket socket = serverSocket.accept();
            //3.获得的输入流
            InputStream is = socket.getInputStream();
            //获得流:可以对对象进行反序列化
            ObjectInputStream ois = new ObjectInputStream(is);
            //获得输出流:
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            //4.读取用户输入信息
            User user = (User)ois.readObject();
            out.print("用户信息:"+user.getLoginName);
            //给客户一个响应
            String reply = "Welcome!";
            pw.write(reply);
            pw.flush();
            //5.关闭资源
            pw.close();
            os.close();
            ois.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e){
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        }        
    }
}

LoginClient.java

/** * 客户端类 */
public class LoginClient{
    main(){
        try{
            //1.建立客户端Socket连接,指定服务器的位置及端口
            Socket socket = new Socket("localhost",8080);
            //2.得到Socket的读写流
            OutputStream os = socket.getOutputStream();
            //对象序列化流
            ObjectOutputStream oos = new ObjectOutputStream(os);
            //输入流
            InputStream is = socket.getInputStream();
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //3.利用流按照一定的协议对Socket进行读/写操作
            User user = new User();
            user.setLoginName("Zhangsan");
            oos.writeObject(user); 
            socket.shudownOutput();
            //接受服务器的响应并打印显示
            String reply = null;
            while(!(reply=br.readLine())==null){
                out.print("这是客户端,服务器的响应为:"+reply);
            }
            //4.关闭资源
            br.close();
            is.close();
            oos.close();
            os.close();
            socket.close();
        }
    }

}

多用户同时访问服务器

一个客户访问启动一个线程,一个Socket对应一个线程。

线程类:ServerThread

/** * 线程相关类 */
public class ServerThread extends Thread{
    //和本线程相关的Socket
    Socket socket = null;

    //通过创建线程的过程,可以实现一个新的线程和一个Socket绑定的过程
    public serverThread(Socket socket){
        this.socket = socket ; 
    }
    //线程启动:响应用户请求
    public void run(){
        try{
            //3.获得的输入流
            InputStream is = socket.getInputStream();
            //获得流:可以对对象进行反序列化
            ObjectInputStream ois = new ObjectInputStream(is);
            //获得输出流:
            OutputStream os = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(os);
            //4.读取用户输入信息
            User user = (User)ois.readObject();
            out.print("用户信息:"+user.getLoginName);
            //给客户一个响应
            String reply = "Welcome!";
            pw.write(reply);
            pw.flush();
            //5.关闭资源
            pw.close();
            os.close();
            ois.close();
            socket.close();
            serverSocket.close();
        } catch (IOException e){
            e.printStackTrace();
        } catch(IOException e){
            e.printStackTrace();
        }   
    }

}

LoginServer.java

/** * 服务器类 */
public class LoginServer{
    main(){

        try{
            //1.建立一个服务器Socket(ServerSocket)绑定指定端口并开始监听
            ServerSocket serverSocket = new ServerSocket(8800);
            //2.使用accept()方法阻塞等待监听,获得新的连接
            Socket socket = null;
            //声明一个变量,监听客户数量
            int num = 0;
            //一直处于监听状态
            while(true){
                socket = serverSocket.accept();
                ServerThread serverThread = new ServerThread(socket);
                //启动线程
                serverThread.start();
                num++;
                out.print("客户数量"+num);

                //客户的IP信息
                InetAddress ia = socket.getInetAddress();
                //客户的IP
                String ip = ia.getHostAddress();
                out.print("本客户的IP为:"+ip);
                //客户的主机名称
                String hostName = ia.getHostName();
                out.print("本客户的主机为为:"+hostName);
            }

        } catch (IOException e){
            e.printStackTrace();
        }    
    }
}

3、Socket类以及ServerSocket类如何使用(*)

源码参照上部分;

4、InetAddress类如何使用(获取IP和hostName)

源码参照上部分;
Socket网络编程_第4张图片

二、基于UDP协议的Socket编程

Socket网络编程_第5张图片

1、DatagramSocket类如何使用

Socket网络编程_第6张图片

Socket网络编程_第7张图片

Socket网络编程_第8张图片

服务器端:AskServer

/** * 服务器端 */
public class AskServer{
    main(){
        try{
            //1.创建接受方(服务器)套接字,并绑定端口号
            DatagramSocket ds = new DatagramSocket(8800);
            //2.确定数据包接受的数据的数组大小
            Byte[] buf = new byte[1024];
            //3.创建接受类型的数据包,数据将存储在数组中
            DatagramPacket dp = new DatagramPacket(buf, buf.length);
            //4.通过套接字接受数据
            ds.receive(dp);
            //5.解析发送方法的数据
            String mess = new String(buf,0,dp.getLength());
            out.print("客户端:"+mess);
            //响应客户端
            String reply = "服务端响应客户端:!!!";
            byte[] replys = reply.getBytes();
            //响应地址
            SocketAddress sa = dp.getSocketAddress();
            //数据包
            DatagramPacket dp2 = new DatagramPacket(replys,replys.length,sa);
            //发送
            ds.send(dp2);
            //6.释放资源
            ds.close();
        }catch(SocketException e){

        }catch(IOException e){

        }
    }
}

客户端:AskClient

/** * 客户端 */
public class AskClient{
    main(){
        //1.确定发送给服务器的信息,服务器地址以及端口
        String mess = "一个问题!";
        byte[] buf = mess.getBytes();
        IntAddress ia = null;
        try{
            ia = InetAddress.getByName("localhost");
        }catch(UnknownHostException e){

        }
        //端口
        int port = 8800;
        //2.创建数据包,发送指定长度的信息到指定服务器的指定端口
        DatagramPacket dp = new DatagramPacket(buf, buf.length,ia,port);
        //3.创建DatagramSocket对象
        DatagramSocket ds = null;
        try{
            ds = new DatagramSocket();
        }catch(){

        }
        //4.向服务器发送数据包
        try{
            ds.send(dp);
        }catch(){
        }
        //接受服务器的响应并打印
        byte[] buf2 = new byte[1024];
        DatagramPacket dp2 = new DatagramPacket(buf2,buf2.length);
        //通过套接字接受数据
        try{
            ds.receive(dp2);
        }
        //解析服务器的响应
        String reply = new String(buf2,0,dp2.getLength());
        out.print("服务器端的响应为:"+reply);

        //5.释放资源
        ds.close();
    }

}

2、DatagramPacket类如何使用

Socket网络编程_第9张图片

源码参照上部分;

三、总结

3.1服务器编程步骤:

  1. 建立服务器Socket绑定指定端口开始监听
  2. 使用accept()方法阻塞等待监听,获得连接
  3. 建立输入和输出流
  4. 在已有的协议上产生回话
  5. 使用close()关闭流和Socket

3.2客户端编程步骤:

  1. 建立Socket连接,指定服务器位置及端口
  2. 得到Socket的读写流
  3. 利用流按一定的协议对Socket读/写操作
  4. 使用close()关闭流和Socket

你可能感兴趣的:(Java程序开发)