网络编程

网络模型

OSI七层参考模型和TCP/IP四层参考模型
主机至网络层(物理层 , 数据链路层) , 网际层 , 传输层 , 应用层(应用层 , 表示层 , 会话层)

物理层:主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。
数据链路层:主要将从物理层接收的数据进行MAC地址(网卡的地址)的封装与解封装。常把这一层的数据叫做帧。在这一层工作的设备是交换机,数据通过交换机来传输。
网络层:主要将从下层接收到的数据进行IP地址(例192.168.0.1)的封装与解封装。在这一层工作的设备是路由器,常把这一层的数据叫做数据包。
传输层:定义了一些传输数据的协议和端口号(WWW端口80等),如:TCP、UDP等。
会话层:通过传输层(端口号:传输端口与接收端口)建立数据传输的通路。主要在你的系统之间发起会话或者接受会话请求。
表示层:主要是进行对接收的数据进行解释、加密与解密、压缩与解压缩等(也就是把计算机能够识别的东西转换成人能够能识别的东西(如图片、声音等)。
应用层: 主要是一些终端的应用,比如说FTP(各种文件下载),WEB(IE浏览),QQ之类的(可以把它理解成我们在电脑屏幕上可以看到的东西.就是终端应用)。

网络编程三要素

IP地址:网络中设备的标识
在Java中,InetAddress类表示互联网协议 (IP) 地址。
我么可以使用该类中的一些方法获取主机名,或者IP地址。

端口号: 用于标识进程的逻辑地址,每个网络程序都会有一个逻辑端口。端口的取值范围为0~65535(两个字节),其中0 ~1023系统使用或保留端口。

传输协议: 通讯的规则常见协议有TCP,UDP

传输协议

UDP
将数据、数据源、目的地封装到数据包中,不需要建立连接,每个数据包的大小限制在64k内。在发送数据后,如果目的地存在,就接收,不存在就将数据丢掉。
因为无连接,是不可靠协议,速度快。
TCP
建立连接,形成传输数据的通道,在连接中进行大数据量传输。是可靠协议,效率较低。
Socket就是为网络服务提供的一种机制,通信的两端都有Socket,网络通信其实就是Socket间的通信,数据在两个Socket间通过IO传输

UDP传输

DatagramSocket类表示用来发送和接收数据报包的套接字。
public void receive(DatagramPacket p) throws IOException
从此套接字接收数据报包。
public void send(DatagramPacket p) throws IOException
从此套接字发送数据报包

DatagramPacket类表示数据报包,数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
public DatagramPacket(byte[] buf,int length)
构造DatagramPacket,用来接收长度为length的数据包。

步骤:

  1. 建立UDPSocket服务(找端点)
  2. 提供数据,将数据封装到数据包中
  3. 通过Socket服务的发送功能,将数据包发送出去
  4. 关闭资源
//发送端
import java.io.IOException;
import java.net.*;

public class UDPSendDemo {
    public static void main(String[] args) throws IOException {
        //创建UDP服务,通过DatagramSocket对象
        //发送端可以使用默认端口
        DatagramSocket ds = new DatagramSocket();
        //将数据封装成数据包
        byte[] bytes = "Hello UDP".getBytes();
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.47.102"), 9999);
        //通过Socket服务,通过send方法将已有的数据包发送出去
        ds.send(dp);
        //关闭资源
        ds.close();
    }
}

步骤:

  1. 定义UDPSocket服务,通常会监听一个端口,给接收网络应用程序定义一个标识。方便于明确哪些数据过来该应用程序可以处理。如果不指定端口标识,系统会自动分配一个端口,但是该端口与发送端的目标端口可能不一致,最终导致数据丢失。
  2. 定义一个数据包存储接收到的数据,利用数据包对象的方法提取字节数据的信息
  3. 通过Socket服务的receive方法将收到的数据存入定义好的数据包中
  4. 通过数据包对象的特有功能,将数据取出,打印在控制台上
  5. 关闭资源
//接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceiveDemo {
    public static void main(String[] args) throws IOException {
        //1.创建UDPSocket服务,建立端点
        //创建数据报套接字并将其绑定到本地主机上的指定端口。
        DatagramSocket ds = new DatagramSocket(9999);
        //2.定义数据包,用于存储数据
        byte[] bytes=new byte[1024];
        DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
        //3.通过服务的receive方法,将收到的数据存入数据包中
        //阻塞的方法,如果数据没过来,就等待在这里。
        ds.receive(dp);
        //4.通过数据包的方法获取其中的数据
        String address = dp.getAddress().getHostAddress();
        String data = new String(dp.getData(), 0, dp.getLength());
        int port = dp.getPort();

        System.out.println(address+"::"+data+"::"+port);
        //5.关闭资源
        ds.close();
    }
}

UDP将键盘录入内容从发送端传输到接收端

//发送端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class UDPSendDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String line=null;
        while ((line=reader.readLine())!=null){
            if ("886".equals(line))
                break;
            byte[] bytes = line.getBytes();
            //ip:"192.168.1.255" 为广播地址,给网络段中的所有机器发送消息
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.47.102"),8888);
            ds.send(dp);
        }
        
        ds.close();
    }
}
//接收端
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class UDPReceiveDemo {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket(8888);
        System.out.println("等待接收数据");
        while (true){
            byte[] bytes = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
            ds.receive(dp);
            byte[] data = dp.getData();
            String str = new String(data,0,dp.getLength());
            if (str.equals("over"))
                break;
            System.out.println(str);
        }
        ds.close();
    }
}

UDP传输通过多线程实现聊天室程序

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;

public class ChatDemo {
    public static void main(String[] args) throws SocketException {
    /*收取数据和发送数据两部分同时进行就需要使用多线程技术。
	一个线程收取数据,一个线程发送数据。
	因为收发动作不一致,需要定义两个run方法,这两个方法要封装在不同的类中。
    */
        DatagramSocket sendSocket = new DatagramSocket();
        DatagramSocket receiveSocket = new DatagramSocket(10000);

        new Thread(new Send(sendSocket)).start();
        new Thread(new Receive(receiveSocket)).start();
    }
}

class Send implements Runnable{
    private DatagramSocket ds;

    public Send(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            String line=null;

            while ((line=reader.readLine())!=null){
                byte[] bytes = line.getBytes();
                DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("192.168.0.102"),10000);
                ds.send(dp);
            }
        }catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

class Receive implements Runnable{
    private DatagramSocket ds;

    public Receive(DatagramSocket ds) {
        this.ds = ds;
    }

    @Override
    public void run() {
        try {
            while (true){
                byte[] bytes = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
                ds.receive(dp);

                String hostName = dp.getAddress().getHostName();

                System.out.println(hostName+"..."+new String(dp.getData(),0,dp.getLength()));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
TCP传输

public Socket(InetAddress address,int port) throws IOException
创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
public InputStream getInputStream() throws IOException
返回此套接字的输入流。
public OutputStream getOutputStream() throws IOException
返回此套接字的输出流。

步骤:

  1. 创建Socket服务并指定要链接的主机和端口
  2. 获取Socket流中的输出流,将数据写到该流中,通过网络发送给服务端。
  3. 关闭客户端资源
//客户端
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws IOException {
        //创建客户端的Socket服务,指定目的主机和端口。
        //如果通路建立成功,就会产生Socket流,包含输入流和输出流,可读写数据
        Socket socket = new Socket("192.168.0.102", 10001);

        //为了发送数据,要获取Socket流中的输出流
        OutputStream out = socket.getOutputStream();

        out.write("Hello TCP".getBytes());
        //输出流通过Socket对象获取到的,Socket流关闭了,输出流自然也会被关闭,此处不需要再次关闭
        socket.close();
    }
}

步骤

  1. 建立服务端的Socket服务,通过ServerSocket。并监听一个端口
  2. 通过accept方法获取连接过来的客户端对象,这个方法是阻塞式的,没有连接就会等待
  3. 客户端如果发过来数据,服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据
  4. 关闭服务端(可选操作)
//服务端
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) throws IOException {
       //建立服务端的Socket服务,并监听一个端口
        ServerSocket ss = new ServerSocket(10001);
        //通过accept方法获取链接过来的Socket对象
        //服务端没有流对象,所以要获取客户端的流对象与客户端进行通讯
        Socket socket = ss.accept();
        String hostName = socket.getInetAddress().getHostName();
        System.out.println(hostName+"...connected");
        //获取客户端发送过来的数据,使用客户端对象的读取流来读取数据
        //源为网络流,因为数据从网络中读取到的
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[1024];
        int len=in.read(buf);

        System.out.println(new String(buf,0,len));

        socket.close(); //关闭客户端
        ss.close();
    }
}

注意:在启动时,需要先启动服务端,如果先启动客户端,客户端连接不上服务端就会报错

TCP传输中,客户端和服务端的互访

//客户端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.0.102", 10002);

        OutputStream out = socket.getOutputStream();
        out.write("Hello".getBytes());

        InputStream in = socket.getInputStream();

        byte[] buf = new byte[1024];
        int len= in.read(buf);

        System.out.println(new String(buf,0,len));

        socket.close();
    }
}
//接收端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10002);

        Socket socket = ss.accept();
        String hostName = socket.getInetAddress().getHostName();
        System.out.println(hostName+"...connected");

        InputStream in = socket.getInputStream();
        byte[] buf = new byte[1024];
        int len=in.read(buf);

        System.out.println(new String(buf,0,len));

        OutputStream out = socket.getOutputStream();

        out.write("已接受到数据".getBytes());

        socket.close();
    }
}

客户端键盘录入数据发送到服务端

import java.io.*;
import java.net.Socket;

public class TCPClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.0.102", 9999);
        //定义字符输出流将数据发送给服务端
        OutputStream out = socket.getOutputStream();
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
        //定义字符输入流获取键盘输入的数据
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        //定义一个Socket读取流,读取服务端返回的信息
        InputStream in = socket.getInputStream();
        BufferedReader reader1 = new BufferedReader(new InputStreamReader(in));


        String line=null;
        while ((line=reader.readLine())!=null){
            if ("over".equals(line))
                break;
            writer.write(line);
            //键盘录入时没有换行,readLine读取不到换行符就会一直阻塞,所以要调用newLine方法
            writer.newLine();
            writer.flush();
            String str = reader1.readLine();
            System.out.println("Server:"+str);
        }

        //键盘录入的读取流与Socket无关
        reader.close();
        socket.close();
    }
}

TCP客户端传输文本文件给服务端

import java.io.*;
import java.net.Socket;

public class TextClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("192.168.0.102", 8888);

        BufferedReader reader = new BufferedReader(new FileReader("a.txt"));
        PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);

        String line=null;
        while ((line=reader.readLine())!=null){
            printWriter.println(line);
        }
        /*关闭客户端输出流,相当于给流中加入一个结束标记
         如果没有标记,客户端因为在等待服务端的反馈数据,
         所以处于阻塞状态,无法执行关闭资源的操作
         导致服务端的readLine也处于阻塞状态,还在等待服务端发送数据*/
        socket.shutdownOutput();

        BufferedReader reader1 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String str = reader1.readLine();
        System.out.println(str);

        reader.close();
        socket.close();
    }
}
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class TextServer {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);

        Socket socket = ss.accept();
        String hostName = socket.getInetAddress().getHostName();
        System.out.println(hostName+"...connected");

        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        PrintWriter printWriter = new PrintWriter(new FileWriter("b.txt"), true);
        String line=null;
        while ((line=reader.readLine())!=null){

            printWriter.println(line);
        }
        PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
        pw.println("上传成功");

        printWriter.close();
        socket.close();
        ss.close();
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值