java----网络编程(一)

一.什么是网络编程

用户在浏览器中,打开在线视频网站,如优酷看视频,实质是通过网络,获取到网络上的一个视频资源。
在这里插入图片描述
与本地打开视频文件类似,只是视频文件这个资源的来源是网络。所谓网络资源就是网络中获取数据。而所有的网络资源,都是通过网络编程来进行数据传输的。网络编程,指网络上的主机,通过不同的进程,以编程的方式实现网络通信(或称为网络数据传输)。
在这里插入图片描述
当然,我们只要满足进程不同就行;所以即便是同一个主机,只要是不同进程,基于网络来传输数据,也属于网络编程。

发送端和接收端:
在一次网络数据传输时:发送端:数据的发送方进程,称为发送端。发送端主机即网络通信中的源主机。
接收端:数据的接收方进程,称为接收端。接收端主机即网络通信中的目的主机。
收发端:发送端和接收端两端,也简称为收发端。
注意:发送端和接收端只是相对的,只是一次网络数据传输产生数据流向后的概念。

在这里插入图片描述

请求和响应:

一般来说,获取一个网络资源,涉及到两次网络数据传输。第一次:请求数据的发送。第二次:响应数据的发送。

客户端和服务端:

服务端:在常见的网络数据传输场景下,把提供服务的一方进程,称为服务端,可以提供对外服务。
客户端:获取服务的一方进程,称为客户端。对于服务来说,一般是提供:
客户端获取服务资源和客户端保存资源在服务端。

在这里插入图片描述

常见的客户端服务端模型:

最常见的场景,客户端是指给用户使用的程序,服务端是提供用户服务的程序:1. 客户端先发送请求到服务端。2. 服务端根据请求数据,执行相应的业务处理。3. 服务端返回响应:发送业务处理结果。4. 客户端根据响应数据,展示处理结果(展示获取的资源,或提示保存资源的处理结果)

二.UDP和Tcp的特点

这里列举的UDP和Tcp只是很简单的一些特点,后面会详细谈论Tcp和UDP。

udp:无连接,不可靠,全双工,面向数据报。
tcp:有连接,可靠,全双工,面向字节流。

有连接和无连接:JDBC会先创建一个DataSource,再通过DataSource建立Connect连接。比如打电话时对方接通才算建立连接成功。
可靠和不可靠:A尽可能的给B传输信息,传输 失败时,A能感知到。可靠和不可靠都有优缺点,可靠传输效率低,不可靠传输效率高,具体用哪一个要看场景。
字节流和数据报:Tcp和文件操作类似,都是以字节传输的,像流一样。
UDP面向数据报,读写的单位是一个UDP数据报(后面介绍)。
全双工半双工:全双工,一个通道可以双向通信。半双工,一个通道只能单向通信。

三.UDP实现客户端服务器

2个核心类DatagramSocket和DatagramPacket

DatagramSocket

DatagramSocket是一个socket对象,操作系统使用文件这样的概念来管理一些软硬件资源。表示网卡的这类文件被称为socket文件,网卡也是操作系统使用文件来控制的。java的socket对象就对应着socket对象。
在这里插入图片描述
第一个构造方法用于客户端,第二个构造方法指定了端口号用于服务器。
为什么服务器要指定一个特定的端口号,而客户端要一个随机的端口号。
比如我要去学校食堂的2号窗口吃饭,学校就是服务器,我就是客户端。为了让学生每次都能找到,我窗口的位置必须是固定的,使用一个固定的端口号。而学生每次吃饭坐的位置不同,上次做的位置可能这次来被别人占用了,所以需要随机分配一个空闲的座位,也就是分配一个随机的端口号。
在这里插入图片描述

第一个方法是接收数据报,第二个发送数据报,第三个关闭。前2个方法都传入了DatagramPacket 类型的方法参数,那么DatagramPacke是什么?

DatagramPacke

DatagramPacke是一个UDP数据报,代表了系统中设定的UDP数据报的二进制形式。
在这里插入图片描述
DatagramPacket作为UDP数据报,必然要能够承载一些数据,通过手动指定byte[]作为数据的存储空间

实现Udp服务器

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

class UdpSever{
    public DatagramSocket socket =null;
    public UdpSever(int port) throws SocketException {
        this.socket=new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("客户端启动");
        while (true){
            DatagramPacket datagramPacket = new DatagramPacket(new byte[1024],1024);
            socket.receive(datagramPacket);
            String str = new String(datagramPacket.getData(),0,datagramPacket.getLength());
           String requsrt = process(str);
           DatagramPacket datagramPacket1 = new DatagramPacket(requsrt.getBytes(),requsrt.getBytes().length,datagramPacket.getSocketAddress());
         socket.send(datagramPacket1);
            System.out.print("["+datagramPacket.getAddress().toString()+" ");
            System.out.print(datagramPacket.getPort()+"]:");
            System.out.print("req:"+str+" ");
            System.out.println("reqs:"+requsrt);
        }
    }
    public String process(String str){
        return str;
    }
}
public class Test3 {
    public static void main(String[] args) throws IOException {
 UdpSever udpSever = new UdpSever(9090);
 udpSever.start();
    }
}

在这里插入图片描述
创建DatagramPacket对象,传入字节数组,DatagramPacket的返回值是一个字节数组,第一句代码运行结束此时并没有把客户端发来的信息写入。socket.reveive才是把客户端发来的信息真正的写入创建的字节数组中。
在这里插入图片描述
因为写入字节数组的内容二进制形式,所以构造字符串把接收到的二进制内容转换为字符串。同时计算出响应。

UDP客户端

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

class Udpclint{
    public DatagramSocket socket=null;
    public String SeverIP;
    public int SeverPort;
    public Udpclint(String SeverIP,int SeverPort) throws SocketException {
        this.SeverIP=SeverIP;
        this.SeverPort=SeverPort;
        this.socket=new DatagramSocket();
    }
    public void start() throws IOException {
        System.out.println("客户端启动:");
        while(true){
            System.out.print("----->");
            Scanner scanner = new Scanner(System.in);
            String str = scanner.next();
            DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(),str.getBytes().length, InetAddress.getByName(SeverIP),SeverPort);
           socket.send(datagramPacket);
           DatagramPacket datagramPacket1 = new DatagramPacket(new byte[1024],1024);
           socket.receive(datagramPacket1);
            String requst = new String(datagramPacket1.getData(),0,datagramPacket1.getLength());
            System.out.println(requst);
        }
    }

}
public class Test4 {
    public static void main(String[] args) throws IOException {
Udpclint udpclint = new Udpclint("127.0.0.1",9090);
udpclint.start();
    }
}

客户端和服务器相互搭配运行效果
在这里插入图片描述
在这里插入图片描述

根据客户端和服务器代码实现翻译功能

分析:字典功能需要客户端输入中文意思,服务器显示英文单词。只需要客户端在计算响应的时候,实现翻译处理,所以让自己实现的翻译类继承服务器类,重写计算响应的方法(process),使其具备翻译功能

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

class GrammerSever extends UdpSever{
    Map<String,String> map = new HashMap<>();
    public GrammerSever(int port) throws SocketException {
       super(port);
       map.put("猫","cat");
       map.put("狗","dog");
       map.put("鱼","fish");

    }

    @Override
    public String process(String str) {
        return map.get(str);
    }
}
public class Test5 {
    public static void main(String[] args) throws IOException {
        GrammerSever grammerSever = new  GrammerSever(9090);
        grammerSever.start();
    }
}

在这里插入图片描述
在这里插入图片描述

Tcp实现

Tcp分量要比Udp更重,用的更多的协议,,Tcp主要有2个类,SeverSocket和socket。给服务器用seversocket,socket既可以客户端使用也可以服务器使用。

Tcp服务器

mport java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class TcpSever{
    public ServerSocket socket = null;
    public ExecutorService executorService = Executors.newCachedThreadPool();
    public TcpSever(int port) throws IOException {
        this.socket=new ServerSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动:");

        while(true){
            Socket socket1 = socket.accept();
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        process(socket1);
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            });


        }
    }
    public void process(Socket socket1) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", socket1.getInetAddress().toString(), socket1.getPort());
        try(InputStream inputStream = socket1.getInputStream();
            OutputStream outputStream = socket1.getOutputStream()) {
            while (true){
                Scanner scanner =new Scanner(inputStream);
                if(!scanner.hasNext()){
                    System.out.printf("[%s:%d] 客户端下线!\n", socket1.getInetAddress().toString(), socket1.getPort());
                    break;
                }
                String requst = scanner.next();
                String requse = process1(requst);
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(requse);
                printWriter.flush();
                System.out.printf("[%s:%d] req: %s, resp: %s\n", socket1.getInetAddress().toString(), socket1.getPort(),
                        requse, requst);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        finally {
            socket1.close();
        }
    }
    public  String process1(String str){
        return str;
    }
}
public class Test {
    public static void main(String[] args) throws IOException {
TcpSever tcpSever = new TcpSever(22);
tcpSever.start();
    }
}

在这里插入图片描述
Tcp首先要处理连接,内核的连接就想一个待办事项,这些待办事项在一个队列的数据结构中,应用程序就需要一个一个完成这些任务,要完成这些任务就得先取任务。
在这里插入图片描述
accept是把内核中已经建立好的连接拿到应用程序中,但是这里的返回值并非是一个connect这样的对象,而只是一个socket对象,这个socket对象就像一个耳麦一样可以说话也可以听到对方的声音。
在这里插入图片描述

Tcp客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

class Tcpclint{
    public Socket socket =null;
    public Tcpclint(String IP,int port) throws IOException {
        this.socket=new Socket(IP,port);
    }
    public void start(){
        System.out.println("客户端启动:");
        try(InputStream inputStream = socket.getInputStream();
            OutputStream outputStream =socket.getOutputStream()) {
            while (true) {
                System.out.print("-------->");
                Scanner scanner = new Scanner(System.in);
                String str = scanner.next();
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(str);
                printWriter.flush();
                Scanner scanner1 = new Scanner(inputStream);
                String str1 = scanner1.next();
                System.out.println(str1);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
public class Test2 {
    public static void main(String[] args) throws IOException {
        Tcpclint tcpclint = new Tcpclint("127.0.0.1",22);
        tcpclint.start();
    }
}

在这里插入图片描述
在这里插入图片描述

Tcp实现单词翻译功能

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

class Grammer extends  TcpSever{
    Map<String,String> map = new HashMap<>();
    public Grammer(int port) throws IOException {
        super(port);
        map.put("猫","cat");
        map.put("狗","dog");
        map.put("鱼","fish");
    }

    @Override
    public String process1(String str) {
        return map.get(str);
    }
}
public class Test7 {
    public static void main(String[] args) throws IOException {
        Grammer grammer =new Grammer(9090);
        grammer.start();
    }
}

在这里插入图片描述
在这里插入图片描述

  • 24
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值