Java网络编程

 博主主页: 码农派大星.

    数据结构专栏:Java数据结构

 数据库专栏:MySQL数据库

JavaEE专栏:JavaEE

关注博主带你了解更多数据结构知识

1.网络初识

1.1基本知识

网络的发展:单机时代-局域网时代-广域网时代-移动互联网时代
局域网:把几个电脑通过一个路由器连接到一起
广域网:把更多的局域网连接在在一起
IP地址:IP地址是 IP协议 提供的一种统一的 地址格式 ,它为互联网上的每一个网络和每一台 主机 分配一个逻辑地址
端口号:不同程序关联了不同的端口号,一个端口号只能绑定一个程序但是一个程序可以绑定多个端口号。
协议:一种约定
五元组:源IP地址,目的IP地址,源端口号,目的端口号,协议类型
协议分层:如果搞一个大的协议来解决所有问题,那么这个协议就会非常的胖达,所以我们就进行拆分,由于通信实在太复杂,拆分出来的小协议就非常多,所以就进行了分层,约定了不同层次之间的调用关系,上层协议调用下层协议,下层协议给上层协议提供支持。

1.2.OSI与TCP/IP 

OSI 七层模型既复杂⼜不实⽤:所以OSI七层模型没有落地、实现. 实际组建⽹络时,只是以OSI七层模型设计中的部分分层,也即是以下TCP/IP五层(或四层)模型来 实现。  

TCP/IP五层(或四层)模型

TCP/IP是⼀组协议的代名词,它还包括许多协议,组成了TCP/IP协议簇。TCP/IP通讯协议采⽤了5层的层级结构,每⼀层都呼叫它的下⼀层所提供的⽹络来完成⾃⼰的需求。

• 应⽤层:负责应⽤程序间沟通,如简单电⼦邮件传输(SMTP)、⽂件传输协议(FTP)、⽹络远 程访问协议(Telnet)等。我们的⽹络编程主要就是针对应⽤层。

• 传输层:负责两台主机之间的数据传输。如传输控制协议(TCP),能够确保数据可靠的从源主机发 送到⽬标主机。

• ⽹络层:负责地址管理和路由选择。例如在IP协议中,通过IP地址来标识⼀台主机,并通过路由表 的⽅式规划出两台主机之间的数据传输的线路(路由)。路由器(Router)⼯作在⽹路层。

• 数据链路层:负责设备之间的数据帧的传送和识别。例如⽹卡设备的驱动、帧同步(就是说从⽹线上 检测到什么信号算作新帧的开始)、冲突检测(如果检测到冲突就⾃动重发)、数据差错校验等⼯作。 有以太⽹、令牌环⽹,⽆线LAN等标准。交换机(Switch)⼯作在数据链路层。

• 物理层:负责光/电信号的传递⽅式。⽐如现在以太⽹通⽤的⽹线(双绞线)、早期以太⽹采⽤的的同 轴电缆(现在主要⽤于有线电视)、光纤,现在的wifi⽆线⽹使⽤电磁波等都属于物理层的概念。物理 层的能⼒决定了最⼤传输速率、传输距离、抗⼲扰性等。集线器(Hub)⼯作在物理层。

⽹络设备所在分层

• 对于⼀台主机,它的操作系统内核实现了从传输层到物理层的内容,也即是TCP/IP五层模型的下四 层;

• 对于⼀台路由器,它实现了从⽹络层到物理层,也即是TCP/IP五层模型的下三层;

• 对于⼀台交换机,它实现了从数据链路层到物理层,也即是TCP/IP五层模型的下两层;

• 对于集线器,它只实现了物理层;

2.网络编程

⽹络编程,指⽹络上的主机,通过不同的进程,以编程的⽅式实现⽹络通信(或称为⽹络数据传 输)我们只要满⾜进程不同就⾏;所以即便是同⼀个主机,只要是不同进程,基于⽹络来传输数 据,也属于⽹络编程

但对于开发来说,在条件有限的情况下,⼀般也都是在⼀个主机中运⾏多个进程来完成⽹络编 程。

2.1 发送端和接收端

在⼀次⽹络数据传输时:

发送端:数据的发送⽅进程,称为发送端。发送端主机即⽹络通信中的源主机。

接收端:数据的接收⽅进程,称为接收端。接收端主机即⽹络通信中的⽬的主机。

收发端:发送端和接收端两端,也简称为收发端。

2.2请求和响应 

获取⼀个⽹络资源,涉及到两次⽹络数据传输:

• 第⼀次:请求数据的发送

• 第⼆次:响应数据的发送。

2.3客⼾端和服务端 

服务端: 在常⻅的⽹络数据传输场景下,把提供服务的⼀⽅进程,称为服务端,可以提供对外服务。

客⼾端:获取服务的⼀⽅进程,称为客⼾端。

2.4 TCP与UDP区别 

传输层提供了2个协议是:TCP和UDP,那有什么区别呢?


TCP是有连接的,UDP是无连接的:TCP保存了对方信息,UDP没有保存
TCP是可靠的,UDP是不可靠的:TCP消息发出能够知道是否到达,UDP不知道。
TCP是面向字节流,UDP是面向数据报:TCP以字节为单位传输,UDP以数据报为单位进行传输
TCP和UDP都是全双工:允许双向通信

 

             

3.Socket API编程 

3.1 UDP网络编程

API接口介绍:

服务端:

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

public class udpechoServer {

    private DatagramSocket socket = null;

    public udpechoServer (int port) throws SocketException {
        socket = new DatagramSocket(port);
    }


    //通过start启动服务器的核心流程
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while(true){
            //此时通过"死循环"不停处理客户端需求


            //1,读取客户端的请求并解析
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //上述收到数据,为二级制byte[]的形式体现的,后续代码如果要进行打印之类的操作
            //需要转成字符串才好处理
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());

            //2.根据请求计算响应,由于此处是回显服务器,响应就是请求
            String response = process(request);
            //3.把响应写回客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(requestPacket);

            //4.打印日志
            System.out.printf("[%s:%d] req = %s, resp=%s\n",requestPacket.getAddress(),requestPacket.getPort(),
                    request,response);

        }
    }

    private String process(String request) {
        return request;
    }

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

    }


}

 客户端:

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

public class udpEchoClient {
    DatagramSocket socket = null;
    private  String serverIP;
    private int serverPort;
    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.从控制台读取到用户输入
            //2构造出一个udp请求,发送给服务器
            //3从服务器读取到响应
            //4把响应打印到控制台
            System.out.println("->");
            String request = scanner.next();
            DatagramPacket requestPacket = new 
            DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(this.serverIP), this.serverPort);
            socket.send(requestPacket);

            DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);


            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.printf(response);
        }
    }

    public static void main(String[] args) throws IOException {
        udpEchoClient client = new udpEchoClient("192.168.0.108",9090);

        client.start();

    }

}

运行结果:

3.2 TCP网络编程

API接口介绍:

服务端: 

import 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;

public class TcpEchoServer {


    private ServerSocket serverSocket = null;

    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("启动服务器!");
        ExecutorService service = Executors.newCachedThreadPool();
        while (true){
           Socket cilentSocket = serverSocket.accept();
           //创建线程,每个线程服务一个客户端
         /*  Thread t = new Thread(()->{
               try {
                   processConnection(cilentSocket);
               } catch (IOException e) {
                   e.printStackTrace();
               }
           });
           t.start();*/
            //使用线程池
            service.submit(()->{

                try {
                    processConnection(cilentSocket);
                }catch (IOException e){
                    throw new RuntimeException(e);
                }
            });

        }
    }

    //针对一个连接,提供处理逻辑
    private void processConnection(Socket cilentSocket) throws IOException {
    //先来打印一下客户端信息
        System.out.printf("[%s:%d] 客户端上线!\n",cilentSocket.getInetAddress(),
               cilentSocket.getPort() );

        try(InputStream inputStream = cilentSocket.getInputStream();
            OutputStream outputStream = cilentSocket.getOutputStream()){
            //使用Scanner包装一下Inputstream,就可以更方便的读取这里的请求数据了
            Scanner scanner = new Scanner(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream);
            while (true){
                //1,读取请求并解析

                if(!scanner.hasNext()){
                    //如果scanner无法读取出数据,说明客户端关闭了连接,导致服务器这边读取到"末尾"
                    break;
                }
                String request = scanner.next();
                //2,根据请求计算响应
                String response = process(request);

                //3,把响应写回客户端
                //此处可以按照字节数组直接来写,也可以有另外一种写法
                //outputStream.write(response.getBytes());
                printWriter.println(response);
                printWriter.flush();
                //4,打印日志
                System.out.printf("[%s:%d] req = %s; resq = %s\n",cilentSocket.getInetAddress(),
                        cilentSocket.getPort(),request,response);
            }

        }catch (IOException e){
            e.printStackTrace();
        }finally {
            System.out.printf("[%s:%d] 客户端下线!\n",cilentSocket.getInetAddress(),
                    cilentSocket.getPort());
            cilentSocket.close();
        }


    }

    private String process(String request) {

        return request;
    }

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

}

客户端:

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

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        socket = new Socket(serverIp,serverPort);
    }
    public void start(){
        System.out.println("客户端启动!");
    try(InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream()){
        Scanner scanner = new Scanner(inputStream);
        Scanner scannerIn = new Scanner(System.in);
        PrintWriter printWriter = new PrintWriter(outputStream);

        while (true){
            //1.从控制台读取服务器
            System.out.println("->");
            String request = scannerIn.next();
            //2.把请求发送给服务器
            printWriter.println(request);
            printWriter.flush();

            //3.从服务器读取响应
            if(!scanner.hasNext()){
                break;
            }
            String response = scanner.next();
            //4,打印响应结果
            System.out.println(response);
        }


        }catch (Exception e) {
        throw new RuntimeException(e);

        }

    }

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

        client.start();
    }
}

运行结果:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值