zoukankan      html  css  js  c++  java
  • Socket 相关资料(随笔)

    由于项目上的 http 请求量较大,项目上性能跟不上。于是考虑把 短连接的 http 换成 长连接的tcp 形式 试试效果。

    先 研究了一下 长连接方式。就是要用到 socket 方面的知识。

    package com.bkc.bpmp.common.utils;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 搭建服务器端
    
    a)、创建ServerSocket对象绑定监听端口。
    
    b)、通过accept()方法监听客户端的请求。
    
    c)、建立连接后,通过输入输出流读取客户端发送的请求信息。
    
    d)、通过输出流向客户端发送请求信息。
    
    e)、关闭相关资源。
     * @author ppnie
     *
     */
    public class SocketService
    {
        // 搭建服务器端
        public static void main(String[] args)
            throws IOException
        {
            SocketService socketService = new SocketService();
            // 1、a)创建一个服务器端Socket,即SocketService
            socketService.oneServer();
        }
        
        public void oneServer()
        {
            try
            {
                ServerSocket server = null;
                try
                {
                    server = new ServerSocket(5209);
                    // b)指定绑定的端口,并监听此端口。
                    System.out.println("服务器启动成功");
                    // 创建一个ServerSocket在端口5209监听客户请求
                }
                catch (Exception e)
                {
                    System.out.println("没有启动监听:" + e);
                    // 出错,打印出错信息
                }
                Socket socket = null;
                try
                {
                    socket = server.accept();
                    // 2、调用accept()方法开始监听,等待客户端的连接
                    // 使用accept()阻塞等待客户请求,有客户
                    // 请求到来则产生一个Socket对象,并继续执行
                }
                catch (Exception e)
                {
                    System.out.println("Error." + e);
                    // 出错,打印出错信息
                }
                // 3、获取输入流,并读取客户端信息
                String line;
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                // 由Socket对象得到输入流,并构造相应的BufferedReader对象
                PrintWriter writer = new PrintWriter(socket.getOutputStream());
                // 由Socket对象得到输出流,并构造PrintWriter对象
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                // 由系统标准输入设备构造BufferedReader对象
                System.out.println("Client:" + in.readLine());
                // 在标准输出上打印从客户端读入的字符串
                line = br.readLine();
                // 从标准输入读入一字符串
                // 4、获取输出流,响应客户端的请求
                while (!line.equals("end"))
                {
                    // 如果该字符串为 "bye",则停止循环
                    writer.println(line);
                    // 向客户端输出该字符串
                    writer.flush();
                    // 刷新输出流,使Client马上收到该字符串
                    System.out.println("Server:" + line);
                    // 在系统标准输出上打印读入的字符串
                    System.out.println("Client:" + in.readLine());
                    // 从Client读入一字符串,并打印到标准输出上
                    line = br.readLine();
                    // 从系统标准输入读入一字符串
                } // 继续循环
                
                // 5、关闭资源
                writer.close(); // 关闭Socket输出流
                in.close(); // 关闭Socket输入流
                socket.close(); // 关闭Socket
                server.close(); // 关闭ServerSocket
            }
            catch (Exception e)
            {// 出错,打印出错信息
                System.out.println("Error." + e);
            }
        }
    }
    
    
    package com.bkc.bpmp.common.utils;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.Socket;
    
    public class SocketClient
    {
        // 搭建客户端
        public static void main(String[] args)
            throws IOException
        {
            try
            {
                // 1、创建客户端Socket,指定服务器地址和端口
                // Socket socket=new Socket("127.0.0.1",5200);
                Socket socket = new Socket("192.168.1.99", 5209);
                System.out.println("客户端启动成功");
                // 2、获取输出流,向服务器端发送信息
                // 向本机的52000端口发出客户请求
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                // 由系统标准输入设备构造BufferedReader对象
                PrintWriter write = new PrintWriter(socket.getOutputStream());
                // 由Socket对象得到输出流,并构造PrintWriter对象
                // 3、获取输入流,并读取服务器端的响应信息
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                // 由Socket对象得到输入流,并构造相应的BufferedReader对象
                String readline;
                readline = br.readLine(); // 从系统标准输入读入一字符串
                while (!readline.equals("end"))
                {
                    // 若从标准输入读入的字符串为 "end"则停止循环
                    write.println(readline);
                    // 将从系统标准输入读入的字符串输出到Server
                    write.flush();
                    // 刷新输出流,使Server马上收到该字符串
                    System.out.println("Client:" + readline);
                    // 在系统标准输出上打印读入的字符串
                    System.out.println("Server:" + in.readLine());
                    // 从Server读入一字符串,并打印到标准输出上
                    readline = br.readLine(); // 从系统标准输入读入一字符串
                } // 继续循环
                  // 4、关闭资源
                write.close(); // 关闭Socket输出流
                in.close(); // 关闭Socket输入流
                socket.close(); // 关闭Socket
            }
            catch (Exception e)
            {
                System.out.println("can not listen to:" + e);// 出错,打印出错信息
            }
        }
        
    }

    这是一个简单的 用java 实现 socket 客户端与服务端的 代码。

    但是这样的例子,并不能实际运用与项目之中。在实际项目中需要考虑到 套接字的连接什么时候关闭,流什么时候关闭,参数的传入与信息的响应都需要得到结果。

    若是这里使用的方法同 http 的话,应该是 一个请求一个对应的响应结果,若是长连接,应该如何把多线程与长连接 结合起来呢?

    现在的项目是 使用C++ 服务端 和 java 客户端  来使用 socket 进行通信。

    C++ 与 Java 之间的通信还涉及到了一个 网络字节码 不一致的问题。以及 还有一个 自定义协议 的问题

    假设 自定义协议 为  

    java 客户端代码(至于这里的BytePtr ,就是  网络字节码 的转码)

    public class BytePtr {
    
        public static byte[] toLH(short n) {  
            byte[] b = new byte[2];  
            b[0] = (byte) (n & 0xff);  
            b[1] = (byte) (n >> 8 & 0xff);  
            return b;  
          }
        
        public   static   byte [] toLH( int  n) {  
            byte [] b =  new   byte [ 4 ];  
            b[0 ] = ( byte ) (n &  0xff );  
            b[1 ] = ( byte ) (n >>  8  &  0xff );  
            b[2 ] = ( byte ) (n >>  16  &  0xff );  
            b[3 ] = ( byte ) (n >>  24  &  0xff );  
            return  b;  
          }  
        
        public static byte[] addBytes(byte[] data1, byte[] data2) {  
            byte[] data3 = new byte[data1.length + data2.length];  
            System.arraycopy(data1, 0, data3, 0, data1.length);  
            System.arraycopy(data2, 0, data3, data1.length, data2.length);  
            return data3;  
          
        }
    }
    
    import java.io.DataInputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    import java.util.Scanner;
    
    public class ChatClient
    {
        
        public static void main(String[] args)
        {
            try
            {
                Socket client = new Socket("192.168.1.108", 10008);
                OutputStream out = client.getOutputStream();
                DataOutputStream outs = new DataOutputStream(out);
                Scanner scaner = new Scanner(System.in);
                genProtocol(outs, scaner.next());
                parseProtocol(client);
                
                outs.close();
                out.close();
                client.close();
            }
            catch (UnknownHostException e)
            {
                e.printStackTrace();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
        
        /**
         * 构造协议
         *
         * @param out
         * @param msg
         * @throws IOException
         */
        private static void genProtocol(DataOutputStream out, String msg)
            throws IOException
        {
            short type = 10001; // 消息类型
            byte[] bytes = msg.getBytes(); // 消息内容
            int totalLen = bytes.length; // 消息长度
            out.write((BytePtr.addBytes(BytePtr.addBytes(BytePtr.toLH(type), BytePtr.toLH(totalLen)), bytes))); // 写入消息内容
            out.flush();
        }
        
        private static void parseProtocol(Socket client)
            throws IOException
        {
            InputStream is = client.getInputStream();
            DataInputStream dis = new DataInputStream(is); // 读取Java标准数据类型的输入流
            
            // 协议解析
            
            int totalLen = dis.readInt(); // 读取消息长度
            byte[] data = new byte[totalLen]; // 定义存放消息内容的字节数组
            int len = is.read(data);
            String text = new String(data, 0, len);
            System.out.println("发来的内容是:" + text);
            
            is.close();
            dis.close();
        }
        
    }

    哦,这里还提到 一个工具 Wireshark,用来抓取包,来查看一下网络字节码到底传送的是一些什么

     

    哦,还有  提到的 netty  技术,至于怎么用,还是先看看再说。

    至于 有一些电子书之类的,可以 到脚本之家 去下载。

    最最重要的一点,下载的电子书、视频、源码 之类的,一定要看啊。

  • 相关阅读:
    使用 requests 维持会话
    使用 requests 发送 POST 请求
    使用 requests 发送 GET 请求
    requests 安装
    使用 urllib 分析 Robots 协议
    使用 urllib 解析 URL 链接
    使用 urllib 处理 HTTP 异常
    使用 urllib 处理 Cookies 信息
    使用 urllib 设置代理服务
    按单生产程序发布
  • 原文地址:https://www.cnblogs.com/panie2015/p/8494227.html
Copyright © 2011-2022 走看看