Java - 网络编程

网络基础

网络

概念:两台设备之间通过网络实现数据传输

网络通信:将数据通过网络从一台设备传输到另一台设备

Java.net包下提供了一系列的类或接口

IP地址

概念:用于唯一标识网络中的每台计算机

查看IP地址:ipconfig

IP地址的表示形式:点分十进制,xx.xx.xx.xx

每个十进制数的范围:0 - 255

IP地址的组成 = 网络地址 + 主机地址 ; 例如:192.168.16.96

IPv6是互联网工程任务组设计的用于替代IPv4的下一代IP协议

域名

为了方便记忆,解决记ip的困难

概念:将IP地址映射成域名(HTTP协议)

端口

概念:用于标识计算机上某个特定的网络程序

标识形式:以整数形式,范围0-65535

0-1024已被占用:如ssh 22,ftp 21,http 80

常见网络程序端口号:

  • tomcat:8080
  • mysql:3306
  • oracle:1521
  • sqlserver:1443

网络通讯协议

TCP/IP (传输控制协议/因特网协议)

是Internet最基本的协议,由网络层的IP协议和传输层的TCP协议组成的

TCP 和 UDP

TCP协议:

  • 使用TCP协议前,需要先建立TCP连接,形成传输数据通道
  • 传输前,采用三次握手方式,是可靠传输
    • A:发送连接请求
    • B:收到连接请求,确认连接请求
    • A:确认连接请求,建立连接
  • TCP协议进行通信的两个应用进程:客户端,服务端
  • 传输完毕,需释放已建立的链接,效率低

UDP协议:

  • 将数据,源,目的封装成数据包,不需要建立连接
  • 每个数据的大小限制在64k内
  • 因无需连接,所以是不可靠传输
  • 发送数据结束时无需释放资源,速度快

InetAddress类

相关方法

  • 获取本机InetAddress对象:getLocalHost ( )(不可new ,直接使用方法获取)
  • 根据指定主机名/域名获取IP地址对象:getByName( )
  • 获取本机InetAddress对象的主机名:getHostName( )
  • 获取本机InetAddress对象的地址:getHostAddress( )

Socket

基本介绍:

套接字(Socket),开发网络应用程序被广泛使用,以至于成为事实上的标准

通信的两端都要有Socket,是两台机器间通信的端点

网络通信其实就是Socket之间的通信

Socket允许程序把网络连接当成一个流,数据在Socket之间通过IO传输

一般主动发起通信的应用程序属客户端,等待通信请求的为服务端

场景1:client向服务端发送一个信息

服务端

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
    public static void main(String[] args) throws IOException {
//        在本机的9999端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);

//        当没有客户端连接9999端口时,程序阻塞,等待连接
        System.out.println("server 9999 listening");
        Socket socket =  serverSocket.accept();

//        打印从client接收到的信息
        InputStream inputStream = socket.getInputStream();
        byte[] buf  = new byte[1024];
        int readLine = 0;
        while ((readLine = inputStream.read(buf)) != -1){
            System.out.println(new String(buf,0,readLine));
        }


//        关闭流
        inputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("server exit");
    }
}

客户端

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class MainClient {
    public static void main(String[] args) throws IOException, InterruptedException {
//        连接本机的9999端口号
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("client 9999 start,server connet");

//        发送信息到服务端
        OutputStream outputStream =  socket.getOutputStream();
        outputStream.write("from client : hello server ".getBytes());

//        关闭流
        outputStream.close();
        socket.close();
        System.out.println("client exit");

    }
}

场景2:字节流互发信息

互发信息必须有一个输出完毕和接收完毕的标记,否则会程序无法知道某方是否已经结束输出而导致阻塞

设置结束标记,表示已经接受完毕:

socket.shutdownInput();  

设置结束标记,表示已经输出完毕:

socket.shutdownOutput();

服务端

package Socket2;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
    public static void main(String[] args) throws IOException {
//        在本机的9999端口监听,等待连接
        ServerSocket serverSocket = new ServerSocket(9999);

//        当没有客户端连接9999端口时,程序阻塞,等待连接
        System.out.println("server 9999 listening");
        Socket socket =  serverSocket.accept();

//        打印从client接收到的信息
        InputStream inputStream = socket.getInputStream();
        byte[] buf  = new byte[1024];
        int readLine = 0;
        while ((readLine = inputStream.read(buf)) != -1){
            System.out.println(new String(buf,0,readLine));
        }

//      设置结束标记,表示已经接收完毕
        socket.shutdownInput();

//        获取socket相关联的输出流
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("from server : hello client ".getBytes());

//      设置结束标记,表示已经输出完毕
        socket.shutdownOutput();



//        关闭流
        inputStream.close();
        outputStream.close();
        socket.close();
        serverSocket.close();
        System.out.println("server exit");
    }
}

客户端

package Socket2;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class MainClient {
    public static void main(String[] args) throws IOException, InterruptedException {
//        连接本机的9999端口号
        Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
        System.out.println("client 9999 start,server connet");

//        发送信息到服务端
        OutputStream outputStream =  socket.getOutputStream();
        outputStream.write("from client : hello server ".getBytes());

//      设置结束标记,表示已经输出完毕
        socket.shutdownOutput();

//        打印从服务器接收到的信息
        InputStream inputStream = socket.getInputStream();
        byte[] buf  = new byte[1024];
        int readLine = 0;
        while ((readLine = inputStream.read(buf)) != -1){
            System.out.println(new String(buf,0,readLine));
        }

//      设置结束标记,表示已经接收完毕
        socket.shutdownInput();




//        关闭流
        outputStream.close();
        inputStream.close();
        socket.close();
        System.out.println("client exit");

    }
}

场景3:图片通过socket从客户端上传保存到服务端某个指定目录

Inputstream转换为byte[ ]的方法类

package Scoker3;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class ToByteArray {

//    将输入流转换成byte[],既可以将文件读入到byte[]
    public static byte[ ] toByteArray(InputStream input) throws IOException {

        ByteArrayOutputStream bos = new ByteArrayOutputStream(); // 创建输出流对象

        byte[] buffer = new byte[1024*4];   // 创建字节数组
        int len = 0;
        while ((len = input.read(buffer))!= -1) { // 循环读取
            bos.write(buffer, 0, len); // 将读取到的数据,写入bos
        }

        byte[] array = bos.toByteArray();// 将bos转换成字节数组
        bos.close();
        return  array;
    }

}

思路:Server

  • 创建 BufferedInputStream bis 套接 socket.getInputStream
  • 创建 byte[ ] bs 读取 bis
  • 创建 BufferedOutputStream bos 套接 FileOutputStream
  • 将 bs 写入 bos,写入磁盘
package Scoker3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class PictureServer {
    public static void main(String[] args) throws IOException {
//        Server监听8888
        ServerSocket serverSocket = new ServerSocket(8888);
//        Server等待连接
        Socket socket = serverSocket.accept();

//        获取到客户端发送的数据
//        通过socket获取输入流,并缓冲
        BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//        将bis转换成byte[]
        byte[] b =  ToByteArray.toByteArray(bis);

//        指定拷贝路径
        String copyFilePath = "D:\\test\\test2.jpg";
//        创建填入路径的 FileOutputStream,并使用bos缓冲
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(copyFilePath));
        bos.write(b);

//        关闭相关流
        bos.close();
        bis.close();
        socket.close();
        serverSocket.close();

    }
}

思路:Client

  • 创建 BufferedInputStream bis 套接jpg的 FileInputStream fis
  • 创建 byte[ ] bs 读取 bis
  • 创建 BufferedOutputStream bos 套接 socket.getOutputStream
  • 将 bs 写入 bos ,发送给服务端
package Scoker3;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class PictureClient {
    public static void main(String[] args) throws IOException {
//        连接服务端8888
        Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//        创建指定图片的FileInputStream,并使用BufferedInputStream bis 套接
        String filePath = "D:\\test\\test.jpg";
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));

//       将缓冲的数据bis 转换成为 byte[] b
        byte[] b =  ToByteArray.toByteArray(bis);

//        通过socket获取到输出流,使用BufferedOutputStream bos 套接,将b数据发送给服务器
        BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());

//        将文件对应的字节数组的内容,写入到数据通道
        bos.write(b);
        socket.shutdownOutput();// 设置了写入数据结束标记


//    关闭相关流
        bis.close();
        bos.close();
        socket.close();

    }


}

场景4:字符流互发信息

字节流读取为字符流

  • 使用InputstreamStreamReader 将 InputStream 转化为字符并指定字符集
  • 再使用BufferReader 套接 InputstreamStreamReader 缓冲
  • 最后使用char[ ] 读取BufferReader

字符流输出为字节流

//        BufferWriter --》 OutputStreamWriter --》 OutputStream

服务端

package Socket4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerHomework {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        Socket socket  = serverSocket.accept();

//       BufferReader --》 InputstreamStreamReader --》 InputStream
        BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"UTF-8"));
        char[] chars = new char[1024];
        int len;
        while ((len = br.read(chars))!= -1){
            System.out.println(new String(chars,0,len));
        }
//       关闭相关流
    }
}

客户端

package Socket4;

import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Scanner;

public class ClientHomework {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket(InetAddress.getLocalHost(),8888);

        Scanner scanner = new Scanner(System.in);
        String ask = scanner.nextLine();

//        BufferWriter --》 OutputStreamWriter --》 OutputStream
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        bw.write(ask);
        bw.newLine();
        bw.flush();
        socket.shutdownOutput();
//       关闭相关流
    }
}

netstat指令

netstat -an 可以查看当前主机网络情况,包括端口监听情况和网络连接情况

netstat -an|more 可以分页显示

说明:

Listening 表示某个端口在监听

如果有一个外部程序连接到该端口,就坏显示一条连接信息

 TCP冷知识

当客户端连接到服务器后,实际上客户端也是通过一个端口和服务端进行通讯的,这个端口是TCP/IP分配的,是不确定的,随机的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值