计算机网络--网络编程(1)

简单认识一下传输层中的UDP和TCP:

TCP:有链接,可靠传输,面向字节流,全双工

UDP:无连接,不可靠传输,面向数据报,全双工


有链接类似于打电话,通了就是有链接。没通就一直在等待。

无连接类似于发短信,只管发,不管到。


可靠传输就是保证信息传输的可靠性。就好比打电话时,你会询问对方在吗,对方回复你,你在发送重要数据给对方。不可靠传输,就好比发短信。假设对方开启了飞行模式,你短信依然能发,但是对方收不收得到,你并不关心也不会询问。


字节流:能按需所取,比如100个字节,可以一个字节一个字节取100次,也能5个字节5个字节的读20次。

数据报:固定的字节数据构成一个数据报,一次只能读取发送一个数据报。


全双工就是双向通信。既能发送也能接收的意思。


简单介绍了TCP,UDP的一些特性,下面我们来看Java中两个重要的网络编程的类。

DatagramSocket API 使用这个类来表示一个对象,在操作系统中,把这个socket对象也是当成一个文件来处理。一个socket对象,就可以和另外一台主机进行通信了。如果要和多个不同的主机进行通信,就得创建多个socket。

DatagramSocket这个类提供了两个构造方法:

计算机网络--网络编程(1)_第1张图片

一个是无参构造方法,相当于只是创建了一个socket,另外一个需要传入一个端口号。 此时就是让当前的socket对象和这个指定的端口,关联起来。无参构造也会分配一个端口号,不过是系统自动分配空闲的端口号。


计算机网络--网络编程(1)_第2张图片

 这两个方法的参数是一个DatagaramPacket.这也是一个类,先来介绍下:

DatagramPacket API  类表示UDP中传输的一个报文。发送方法就是把这个创建好的报文对象发送出去。接收方法的参数是一个空的对象,在receive的内部会对参数的这个空对象进行内容的填充。

用于释放资源的。


DatagramPacket这个类也提供了2个构造方法:

DatagramPacket(byte[] buf, int length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)

 第一个构造方法相当于设置好了一个缓冲区。

第二个构造方法既构造了一个缓冲区又构造了一个地址。


基于这两个API,构造一个最简单的UDP客户端服务器程序。

 服务器端的代码:

package network;
//Udp回显的服务器

import javax.imageio.IIOException;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.nio.charset.StandardCharsets;

public class UdpEchoServer {
    //网络编程的本质是要操作网卡
    //网卡不好直接操作,因此操作系统把socket这样的文件抽象成了网卡
    //因此进行网络通信,势必先有一个socket对象。
    private DatagramSocket socket=null;
    //对于服务器来说,创建socket对象的同时,要让他绑定上一个具体的端口号
    public UdpEchoServer(int port) throws SocketException {
        socket =new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动!!");
        while (true){
            //并不知道有多少个客户端想建立链接,因此写个循环
            //只要有客户端过来,就可以提供服务
            //1.读取客户端发来的请求是啥
            //receive方法,需要一个空白DatagramPacket对象,交给receive来进行填充。填充的数据来自于网卡
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //此时这个DatagramPacket是一个特殊的对象,并不方便直接处理,可以把这里包含的数据拿出来,构成一个字符串
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求计算响应,由于此处是回显服务器,响应和请求相同。
            String response=process(request);
            //3.把回显写回到客户端,send参数也是DatagramPacket 需要把这个Packet对象构造好
            DatagramPacket responsePacket =new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //4.打印请求响应的处理中间结果
            System.out.printf("[%s:%d] req: %s; resp:%s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),
                    request,response);


        }

    }
    //这个方法表示根据请求计算响应
    public String process(String request){
        return request;


    }

    public static void main(String[] args) throws IOException {
       UdpEchoServer server=new UdpEchoServer(9090);
          server.start();

    }

}

这里我们用while循环实现了一直等待客户端发送请求这么一个过程。假设客户端不停的发送请求,并且请求的频率非常快。我这个服务器是否就忙不过来处理了呢?这个情况是很可能出现的。那么解决的方法就是高并发执行。好比我开了一家餐馆,生意不好的时候,我一个人绰绰有余。但是生意非常好。我一个人忙不过来,这个时候我雇了2个人来帮忙。这就是高并发的原理。那么高并发是如何实现呢。那就是通过多线程实现。一个核心一个线程的并发执行。效率就会高很多。但是硬件设施终有上限。那么通过加机器也就就解决这个硬件问题了。


客户端的代码:

package network;

import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;

//Udp回显客户端
public class UdpEchoClient {
    private DatagramSocket socket=null;
    private String serverIp=null;

    private int serverPort=0;
    public UdpEchoClient (String serverIp,int serverPort) throws SocketException {
        socket =new DatagramSocket();
        this.serverIp=serverIp;
        this.serverPort=serverPort;


    }
    public void start()throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner=new Scanner(System.in);
        while (true) {
            //1.从控制台读取要发送的数据
            System.out.print("> ");
            String request =scanner.next();
            if(request.equals("exit")){
                System.out.println("goodbye");
                break;
            }
            //2.构造成UDP请求,并发送,构造这个Packet的时候,需要传入serverIp和port,此处的IP地址是需要一个32位的整数形式
            //而上述的IP是一个字符串,所以需要进行转换
            DatagramPacket requestPacket =new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //3.读取服务器的UDP请求,并解析
            DatagramPacket responsePacket =new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            String response =new String(responsePacket.getData(),0,responsePacket.getLength());
            //4.解析结果显示出来
            System.out.println(response);
        }
    }

    public static void main(String[] args) throws IOException{
        UdpEchoClient client =new UdpEchoClient("127.0.0.1",9090);
        client.start();

    }
}

首先启动我们的服务器:

计算机网络--网络编程(1)_第3张图片

就会进入等待请求的状态。

再启动服务器:

计算机网络--网络编程(1)_第4张图片 我们输入一个hello;

计算机网络--网络编程(1)_第5张图片

 服务器就会给我们回一个hello。我们再看服务器那边:

计算机网络--网络编程(1)_第6张图片

收到了客户端的的IP地址端口号。以上就是实现了一个简单的回显服务器和客户端。

 

你可能感兴趣的:(计算机网络,网络,计算机网络,服务器)