美文网首页
简单的客户端和服务端编程

简单的客户端和服务端编程

作者: HannahLi_9f1c | 来源:发表于2019-11-19 14:48 被阅读0次

TCP

1. 客户端代码

public class TCPEchoClient {
    public static void main(String args[]) throws IOException {
        byte[] data = "123456".getBytes();//获取字节数组
        Socket socket = new Socket("127.0.0.1",8080);//对于客户端来说,需要对服务端发起请求,绑定IP和端口
        InputStream in = socket.getInputStream();//输入流
        OutputStream out = socket.getOutputStream();//输出流
        out.write(data);//向服务端发送数据
        int totalBytesRecd = 0;
        int bytesRecd;
        while(totalBytesRecd < data.length) {
            if((bytesRecd = in.read(data, totalBytesRecd,
                    data.length-totalBytesRecd))==-1) {//读取服务端发送字节流
                throw new SocketException("Connection close prematurely");
            }
            totalBytesRecd+=bytesRecd;
        }
        System.out.println("Recd"+new String(data)+totalBytesRecd);
        socket.close();

    }
}

2. 服务端代码

public class TCPEchoServer {
    public static final int BUFSIZE = 32;
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(8080);//服务端通过固定的端口提供服务,客户端的ip和地址都可以变化,但是服务端需要绑定Ip和服务。
        int recvMsgSize;
        byte[] recvbuf = new byte[BUFSIZE];
        while(true) {
            Socket cliSocket = server.accept();//监听客户端请求,建立起连接
            SocketAddress clientAddress = cliSocket.getRemoteSocketAddress();
            System.out.println("handling client at"+clientAddress);//输出客户端地址
            InputStream inputStream = cliSocket.getInputStream();
            OutputStream outputStream = cliSocket.getOutputStream();
            while((recvMsgSize = inputStream.read(recvbuf)) != -1) {
                outputStream.write(recvbuf, 0 , recvMsgSize);//将受到的字节,写出输出流
            }
            cliSocket.close();
        }

    }
}

3. 解析

  • 通过简单的Java Socket编程,我们可以可以跟TCP的三次握手结合来看。


    image.png

    三次握手的过程中,客户端是作为主动请求方,而服务端的特定服务有确定的Ip和端口,这样每次。比如说80对应HTTP,21对应FTP等等。客户端需要通过一个Socket类表示TCP的一端,里面的参数表明所要连接到的服务端的IP的地址。客户端可以有多个,并且分配的端口是随机的。

  • inputStream,outputStream则是输入流和输出流,Socket的读取和写入,跟文件的读写差不多。但是Socket是要通过网络的
  • 在服务端这边,先是绑定端口,ip就是它的主机地址。它需要有一个ServerSocket来监听客户端请求,也就是用来三次握手建立连接的。当建立起连接之后,需要
    Socket cliSocket = server.accept()来处理连接的任务。所以客户端只需要一个Socket,而服务端需要ServerSocket和Socket。为每一个请求分配一个Socket
  • read()函数为-1发生在客户端或者服务端提前关闭连接的时候

UDP

1. 客户端

public class UDPEchoClient {
    public static final int TIMEOUT = 3000;//超时时间,防止UDP一直阻塞在等待读中,如果一直没有响应,就会发送失败
    public static final int MAXTRIES = 5;//由于数据报文可能丢失,我们必须准备好重新
//传输数据。本例中,我们最多循环5次,来发送数
// 据报文并尝试接收响应信息。
    public static void main(String [] args) throws IOException {
        InetAddress serverAddress = InetAddress.getLocalHost();
        byte[] byteToSend = "123456".getBytes();
        int servePort = 7;
        DatagramSocket socket = new DatagramSocket();
        socket.setSoTimeout(TIMEOUT);
        DatagramPacket sendPacket = new DatagramPacket(byteToSend,
                byteToSend.length, serverAddress, servePort );//发送的报文
        DatagramPacket receivePacket = new DatagramPacket(new byte[byteToSend.length],
                byteToSend.length);//接收报文
        int tries = 0;
        boolean receiveResponse = false;
        do{
            socket.send(sendPacket);
            try {
                socket.receive(receivePacket);
                if (!receivePacket.getAddress().equals(serverAddress)) {
                    throw new IOException("Received form an unknown source");
                }
                receiveResponse = true;
            }catch (InterruptedIOException e) {
                tries +=1;
                System.out.println("Time out");
            }
        } while ((!receiveResponse) && (tries < MAXTRIES));
        if(receiveResponse) {
            System.out.println("Received"+ new String(receivePacket.getData()));
        } else {
            System.out.println("No Response, give up");
        }
        socket.close();

    }
  1. 服务端
public class UDPEchoServer {
    private static final int ECHOMAX = 255;
    public static void main(String [] args) throws IOException {
        int servePort = 7;
        DatagramSocket socket = new DatagramSocket(servePort);
        DatagramPacket packet = new DatagramPacket(new byte[ECHOMAX], ECHOMAX);
        while(true) {
            socket.receive(packet);//接受报文
            System.out.println("Handling client at "+packet.getAddress().getHostAddress()
            +"on port" +packet.getPort());
            socket.send(packet);//复制并返回客户端
            packet.setLength(ECHOMAX);//最大长度255
        }
    }
}

3. 解析

  • UDP与TCP的本质区别就是UDP是面向无连接的,它不需要三次握手,就可以发送报文,在IP的基础上进行数据传输,不保证可靠性传输。所以,应用层需要做好响应的准备,对于数据丢失的相关处理。虽然UDP不可靠,但在很多场景上用处却很大,比如说QQ,DNS这种少量的数据传输。它的好处主要是效率和灵活性。不需要三次握手,所以效率也更高,灵活性是指如果除可靠的字节流服务外,还有其他需求,UDP协议则提供了一个最小开销的平台来满足任何需求的实现。
  • UDP Socket主要是使用DatagramSocket和DatagramPacket,来通信,以及作为IO流。
  • 接收者应该提供一个有足够大
    的缓存空间的DatagramPacket实例,以完整地存
    放调用receive()方法时应用程序协议所允许的最
    大长度的消息。这个技术能够保证数据不会丢失。
    一个DatagramPacket实例中所运行传输的最大数
    据量为65 507字节,即UDP数据报文所能负载的
    最多数据。因此,使用一个有65 600字节左右缓存
    数组的数据包总是安全的。

相关文章

网友评论

      本文标题:简单的客户端和服务端编程

      本文链接:https://www.haomeiwen.com/subject/lniwictx.html