zoukankan      html  css  js  c++  java
  • Socket网络编程


    一、基于TCP协议的Socket编程

    1、Socket(套接字)简介

    这里写图片描述

    Socket——套接字;

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

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

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

    socket1

    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

     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)

    源码参照上部分;
    InetAddress

    二、基于UDP协议的Socket编程

    IUDP

    1、DatagramSocket类如何使用

    UDP1

    datagramSocket

    datagramSocket1

    服务器端: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类如何使用

    datagramPacket

    源码参照上部分;


    三、总结

    3.1服务器编程步骤:

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

    3.2客户端编程步骤:

    1. 建立Socket连接,指定服务器位置及端口
    2. 得到Socket的读写流
    3. 利用流按一定的协议对Socket读/写操作
    4. 使用close()关闭流和Socket
  • 相关阅读:
    java学习路线:给大家讲一个笑话
    谈谈关于IT劳务派遣与人力资源外包的区别!附劳务人力报酬管理目录
    智能化时代来临,CFO们如何才能更管理企业财务!
    谈谈关于创业者和股东成立公司如何出资,出资方式有哪些!附税务管理学习目录
    【创业者关注】初创企业如何节税,节税需要注意哪些?
    谈谈关于财务信息化水平最高的企业是怎样
    谈谈关于技术时代会计信息化的新变革
    谈谈关于IT创业者需要了解初创公司哪些财务管理的常识!
    通过 ML.NET 使用预训练残差网络 ResNet 模型实现手势识别
    1025. 除数博弈-动态规划-简单
  • 原文地址:https://www.cnblogs.com/aixing/p/13327528.html
Copyright © 2011-2022 走看看