• java网络通信


    一、tcp和udp的区别

    1)tcp面向连接(connect,三次握手),udp无连接2) tcp保证可靠(要求对端确认),udp不提供可靠的实时传输

    3)tcp提供流量控制(通告窗口),udp无流量控制

    当然,udp实时,开销小

    二、tcp深入

    1.tcp客户端的流程:

    socket()——>connect()——>write() or read() 完成交互——> close()

    其中,connnect发起主动连接;客户端不需要绑定端口,需要绑定服务器端的ip,(udp里面是数据DatagramPaket自己封装ip和端口)系统会进行自动分配

    2.tcp服务器端的流程:

    socket()——>bind()——>listen()——>accept()——>read() or write()完成交互——>close()

    其中,bind()绑定ip和端口;listen()则把一个未连接的套接口转换成一个被动套接口(创建一个套接口后,被假设为一个主动套接口);accept()等待接收;close()关闭套接口,具体的说,close操作只是使得相应套接字的引用计数减一,只有当计数减少为0的时候,才会触发tcp客户端向服务器发送终止连接请求(主要考虑多线程)。

    3,TCP半关闭

    如果是半关闭(主要因为tcp是全双工的),不使用close,而是利用shutdown(SHUR_WR)

    int shutdown(int sockfd,int howto);其中howto可以为

    SHUT_RD,不能接收数据,当前接收缓冲区的都被丢弃,但仍可写,可以发出数据

    SHUT_WR,不能发出写数据,但仍可读,留在发送缓冲区的数据将被发送到。这成为半关闭

    SHUT_RDWR,同时关闭读和写。

    另外,close只是令计数减1,而shutdown后其他进程将无法利用此套接字通信。

    4,三次握手和四次握手

    tcp建立连接:三次握手:

    以客户端主动建立连接为例:

    1)客户端发送一个SYN J   [connect 函数]

    2)服务器返回一个ACK J+1,发送一个SYN K   [accept 函数,客户端的connect返回]

    3)客户端发挥一个ACK K+1   [accept函数,服务器端的accept函数返回]

    三次握手的原因:防止失效的连接请求报文突然又传送放到服务器。设想这么一种场景:客户端第一次发送的连接请求并没有丢失,而是网络问题导致延迟到达服务器,服务器以为是客户端又发起的新连接,于是同意,并向客户端发挥确认,而客户端不予理会,服务器就一直等待客户端发送请求,导致资源浪费。

    tcp释放连接:四次握手:

    1)一个进程调用close发送FIN,表示数据发送完毕。

    2)另一端在收到FIN后,执行被动关闭,同时发回确认。

    3)一段时间后,另一端调用close发送FIN

    4)接收到FIN的原发送端,对它进行确认。

    四次握手的原因:TCP是全双工的,必须保证每个方向的连接都被释放掉。

    5,利用java语言实现TCP连接

    java利用serverSocket代表服务器端的套接字,其构造函数中同时完成bind绑定

    Socket代表客户端的套接字

    package com.bobo.interview;
    
    import java.io.IOException;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class MyServer {
        private final static int PORT=30000;
        /**
         * @param args
         * @throws IOException 
         */
        public static void main(String[] args) throws IOException {
            ServerSocket server=new ServerSocket(PORT);
            while(true){
                Socket s=server.accept();
                //如果有连接请求,上面的accept函数返回
                PrintStream ps=new PrintStream(s.getOutputStream());
                ps.println("您好,您收到了服务器的信息。。。。");
                ps.close();
                s.close();
            }    
        }
        
         
    
    }
    TCP服务器侧代码
     
    package com.bobo.interview;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class MyClient {
        private final static int PORT = 30000;
        private final static String ip = "127.0.0.1";
    
        /**
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            Socket client = new Socket(ip, PORT);
            BufferedReader br = new BufferedReader(new InputStreamReader(
                    client.getInputStream()));
            System.out.println(br.readLine());
            br.close();
            client.close();
        }
    
    }
    TCP客户端代码

    java里面使用shutdownInput或者shutdownOutput来实现半关闭

    二、udp深入

    udp没有TCP那么复杂的流程,java里面利用DatagramSocket达标udp的套接字,其本身只是码头,负责数据发送,不维护状态;

    UDP严格的说,没有服务器端和客户端之分

    通常创建充当服务器端的DatagramSocket的时候,需要指定端口,充当客户端则使用随机端口

    DatagramSocket发送和接收数据采用的是DatagramPacket,代表数据报,数据报本身指定发送的ip和端口。

    一下是udp通信的java实现:

    package com.bobo.interview;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.SocketException;
    
    public class UDPserver {
        // 服务器端需要指定端口
        private static int PORT = 4096;
        // 指定接收数据的数据报
        private static int DATA_LEN = 4096;
        private static byte[] inBuff = new byte[DATA_LEN];
        private static DatagramPacket inPacket = new DatagramPacket(inBuff,
                inBuff.length);
    
        // 指定发送数据的数据报
        private static DatagramPacket outPacket;
        // 构造发送的数据
        static String outData = "服务器端发送的数据";
    
        /**
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            DatagramSocket udpServer = new DatagramSocket(PORT);
    
            // 利用循环接收数据
            for (int i = 0; i < 1000; i++) {
                udpServer.receive(inPacket);
                System.out.println(inBuff == inPacket.getData());
                System.out.println(new String(inPacket.getData()));
                byte[] sendData = outData.getBytes();
                outPacket = new DatagramPacket(sendData, sendData.length,
                        inPacket.getSocketAddress());
                udpServer.send(outPacket);
    
            }
        }
    
    }
    udp服务器端代码
    package com.bobo.interview;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.net.SocketException;
    
    public class UDPclient {
        // 服务器端需要指定端口
        private static int PORT = 4096;
        private static String ip = "127.0.0.1";
        // 指定接收数据的数据报
        private static int DATA_LEN = 4096;
        private static byte[] inBuff = new byte[DATA_LEN];
        private static DatagramPacket inPacket = new DatagramPacket(inBuff,
                inBuff.length);
    
        // 指定发送数据的数据报
        private static DatagramPacket outPacket;
    
        /**
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            DatagramSocket udpClient = new DatagramSocket(PORT);
            outPacket = new DatagramPacket("客户端发送的数据".getBytes(),
                    "客户端发送的数据".getBytes().length, InetAddress.getByName(ip), PORT);
            udpClient.send(outPacket);
            udpClient.receive(inPacket);
            System.out.println(new String(inPacket.getData()));
        
        }
    
    }
    udp客户端代码

     java实现http通信的代码

    package wzh.Http;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.PrintWriter;
    import java.net.URL;
    import java.net.URLConnection;
    import java.util.List;
    import java.util.Map;
    
    public class HttpRequest {
        /**
         * 向指定URL发送GET方法的请求
         * 
         * @param url
         *            发送请求的URL
         * @param param
         *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
         * @return URL 所代表远程资源的响应结果
         */
        public static String sendGet(String url, String param) {
            String result = "";
            BufferedReader in = null;
            try {
                String urlNameString = url + "?" + param;
                URL realUrl = new URL(urlNameString);
                // 打开和URL之间的连接
                URLConnection connection = realUrl.openConnection();
                // 设置通用的请求属性
                connection.setRequestProperty("accept", "*/*");
                connection.setRequestProperty("connection", "Keep-Alive");
                connection.setRequestProperty("user-agent",
                        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                // 建立实际的连接
                connection.connect();
                // 获取所有响应头字段
                Map<String, List<String>> map = connection.getHeaderFields();
                // 遍历所有的响应头字段
                for (String key : map.keySet()) {
                    System.out.println(key + "--->" + map.get(key));
                }
                // 定义 BufferedReader输入流来读取URL的响应
                in = new BufferedReader(new InputStreamReader(
                        connection.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送GET请求出现异常!" + e);
                e.printStackTrace();
            }
            // 使用finally块来关闭输入流
            finally {
                try {
                    if (in != null) {
                        in.close();
                    }
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
            return result;
        }
    
        /**
         * 向指定 URL 发送POST方法的请求
         * 
         * @param url
         *            发送请求的 URL
         * @param param
         *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
         * @return 所代表远程资源的响应结果
         */
        public static String sendPost(String url, String param) {
            PrintWriter out = null;
            BufferedReader in = null;
            String result = "";
            try {
                URL realUrl = new URL(url);
                // 打开和URL之间的连接
                URLConnection conn = realUrl.openConnection();
                // 设置通用的请求属性
                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent",
                        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
                // 发送POST请求必须设置如下两行
                conn.setDoOutput(true);
                conn.setDoInput(true);
                // 获取URLConnection对象对应的输出流
                out = new PrintWriter(conn.getOutputStream());
                // 发送请求参数
                out.print(param);
                // flush输出流的缓冲
                out.flush();
                // 定义BufferedReader输入流来读取URL的响应
                in = new BufferedReader(
                        new InputStreamReader(conn.getInputStream()));
                String line;
                while ((line = in.readLine()) != null) {
                    result += line;
                }
            } catch (Exception e) {
                System.out.println("发送 POST 请求出现异常!"+e);
                e.printStackTrace();
            }
            //使用finally块来关闭输出流、输入流
            finally{
                try{
                    if(out!=null){
                        out.close();
                    }
                    if(in!=null){
                        in.close();
                    }
                }
                catch(IOException ex){
                    ex.printStackTrace();
                }
            }
            return result;
        }    
    }
    java实现GET和POST方法
  • 相关阅读:
    Android音视频之MediaRecorder音视频录制
    Android数据加密之Des加密
    Java设计模式之模板模式(Template )
    Android图片缓存之Glide进阶
    Android图片缓存之初识Glide
    Android图片缓存之Bitmap详解
    Java设计模式之单例模式(Singleton)
    Java设计模式之工厂模式(Factory)
    Java设计模式之建造者模式(Builder)
    Android okHttp网络请求之Retrofit+Okhttp+RxJava组合
  • 原文地址:https://www.cnblogs.com/bobodeboke/p/3900852.html
Copyright © 2020-2023  润新知