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网络通信,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。