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方法
原文地址:https://www.cnblogs.com/bobodeboke/p/3900852.html