java参数网络传输规则_java学习笔记(10)——网络编程

软件结构

C/S结构:(Client/Server)客户端和服务器结构,常见QQ

5b95dbf89cf5e446f4d2e8c0e4254cd1.png

B/S结构:(Browser/Server)浏览器和服务器结构

75141688fb19e71610d243af2d166085.png

网络通信协议

TCP/IP协议

4层的分层模型

93a69872c61bc97fae78f5780356dcc1.png

协议分类

UDP(用户数据报协议)

无连接通信协议

8b9500f77dfd6f376916afa5d95f225c.png

30ec2f8009d3dc1152f1b24f06e33ea7.png

特点:数据被限制在64kb以内,超出这个范围就不能发送了

数据报(Datagram):网络传输的基本单位

TCP(传输控制协议)

面向连接的通信协议

b474d18681f9126d4a667fb0483e31ab.png

5cd1266a8d5a3f6510d6eca1d942ca66.png

可以保证传输数据的安全

网络编程三要素

协议、IP地址、端口号

1023619d1e20118ccdf217f51e27a442.png

1b10bd5774947ad79ce8625b0c9c8ccf.png

端口号:

逻辑端口,可通过软件查看端口号

网络软件打开时,操作系统会为网络软件分配一个随机的端口号或者网络软件向操作系统要指定的端口号

由两个字节组成:0-65535

1024之前的端口号用户不能使用,已被系统分配给已知网络软件,网络软件端口号不能重复

使用IP地址+端口号,可保证数据准确无误的发送到对方指定软件上

2b432b74791c67bb98d2556e73172a95.png

TCP通信程序

通信步骤:服务端先启动

客户端主动连接服务器端,成功后才能通信;服务端不可主动连接

客户端:

java.net.Socket

创建Socket对象

服务端:

java.net.ServerSocket

创建ServerSocket对象

创建的IO对象为字节流对象

服务器是没有IO流的,但可以获取到请求的客户端对象Socket,使用每个客户端Socket中提供的IO流和客户端进行交互服务器使用客户端的字节输入流读取客户端发送的数据

服务器使用客户端的字节输出流给客户端回写数据

服务器使用客户端的流和客服端交互,利用方法server.accept

8cb4c321f45a907d572ff2f8ea7d54a4.png

Socket类

java.net.Socket

实现客户端套接字,套接字是两台机器间通信的端点

套接字:包含了IP地址和端口号的网络单位

构造方法:Socket(String host, int port)创建一个流套接字并将其连接至指定主机上的指定端口号

参数:

String host:服务器主机的名称/服务器的IP地址

int port:服务器的端口号

成员方法OutputStream getOutputStream()返回套接字的输出流

InputStream getInputStream() 返回套接字的输入流

void close() 关闭套接字

实现步骤:创建一个客户端对象Socket,构造方法绑定服务器的IP地址和端口号

使用Socket对象中getOutputStream方法获取网络字节输出流OutputStream对象

使用网络字节输出流OutputStream对象中write方法,给服务器发送数据

使用Socket对象中的getInputStream方法获取网络字节输入流InputStream对象

使用网络字节输入流InputStream对象中read方法,读取服务器回写的数据

释放资源(Socket)

注意:客户端和服务器端进行交互,必须使用Socket中提供的网络流,禁止使用自己创建的流对象

创建客户端对象Socket时,请求服务器和客户端经过三次握手建立通路服务器未启动,抛出异常

已启动,进行交互public static void main(String[] args) throws IOException {

//Step1

Socket socket = new Socket("127.0.0.1", 8888);

//Step2

OutputStream os = socket.getOutputStream();

//Step3

os.write("你好服务器".getBytes());

//Step4

InputStream is = socket.getInputStream();

//Step5

byte[] bytes = new byte[1024];

int len = is.read(bytes);

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

//Step6

socket.close();

}

ServerSocket类

java.net.ServerSocket

实现客户端套接字,套接字是两台机器间通信的端点

套接字:包含了IP地址和端口号的网络单位

构造方法:ServerSocket(int port)创建绑定到特定端口的服务器套接字

参数:

int port:服务器的端口号

服务器必须明确是哪个客户端请求的服务器

成员方法Socket accept() 侦听并接受到此套接字的连接

实现步骤:创建一个服务器对象ServerSocket对象和系统要指定的端口号

使用ServerSocket对象中accept方法,获取请求的客户端对象Socket

使用Socket对象中getInputStream方法获取网络字节输入流IntputStream对象

使用网络字节输出流getInputStream对象中read方法,读取客户端给服务器的数据

使用Socket对象中的getOutputStream方法获取网络字节输出流OutputStream对象

使用网络字节输入流getOutputStream对象中write方法,给客户端回写数据

释放资源(Socket,ServerSocket)public static void main(String[] args) throws IOException {

//Step1

ServerSocket ss = new ServerSocket(8888);

//Step2

Socket socket = ss.accept();

//Step3

InputStream is = socket.getInputStream();

//Step4

byte[] bytes = new byte[1024];

int len = is.read(bytes);

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

//Step5

OutputStream os = socket.getOutputStream();

//Step6

os.write("thanks".getBytes());

//Step7

socket.close();

ss.close();

}

案例

文件上传案例

d2c2c82ca544ace709a04202c7d0c797.png

客户端

80b25ab7185b7403879bf1934d4558a1.pngpublic static void main(String[] args) throws IOException {

//Step1:本地流读取文件

FileInputStream fis = new FileInputStream("E:\\A JI\\program\\java\\学习路线.png");

FileOutputStream fos = new FileOutputStream("E:\\A JI\\program\\java\\学习路线12.png");

//Step2:创建Socket对象,绑定服务器的端口号和IP地址

Socket socket = new Socket("127.0.0.1", 8888);

//Step3:获取网络字节输出流OutputStream对象

OutputStream os = socket.getOutputStream();

//Step4:本地字节输入流FileInputStream对象的read,读取本地文件

int len = 0;

byte[] bytes = new byte[1024];

while((len = fis.read(bytes)) != -1) {

//Step5:使用网络字节输出流OutputStream对象的write方法,上传到服务器

os.write(bytes, 0, len);

}

//Step6:Socket方法getInputStream,获取网络字节输入流InputStream对象

InputStream is = socket.getInputStream();

//Step7:网络字节输入流InputStream对象中read方法读取服务器回写数据

while((len = is.read(bytes)) != -1) {

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

//从服务器接收的数据放置文件中

fos.write(bytes);

}

//Step8:释放资源

fis.close();

socket.close();

}

服务器端

cc1c4b50e8ba4d9ea95ad3bfa8e62618.pngpublic static void main(String[] args) throws IOException {

//Step1

ServerSocket ss = new ServerSocket(8888);

//Step2

Socket socket = ss.accept();

//Step3

InputStream is = socket.getInputStream();

//Step4

File file = new File("E:\\A JI\\program\\java\\test-txt");

if (!file.exists()) {

file.mkdir();

}

//Step5

FileOutputStream fos = new FileOutputStream(file + "\\1.jpg");

//Step6

int len = 0;

byte[] bytes = new byte[1024];

while((len = is.read(bytes)) != -1) {

//Step7

fos.write(bytes, 0, len);

}

//Step8、Step9

OutputStream os = socket.getOutputStream();

os.write("上传成功".getBytes());

fos.close();

socket.close();

ss.close();

}

两程序都未能停止:

进入阻塞状态,read方法在无输入可用的情况,进入阻塞状态

客户端中read读取文件时,虽然读取到-1停止,但是-1并没有进入while循环,也就没有把结束标记写给服务器

服务器回写也就没有结束标记,客户端接收read就没有结束标记,进入阻塞状态

74171757090bb1e1f5be61bb57965a64.png

af25c700f2803b08efee8779eb7d1c15.png

解决方法:

客户端上传完文件,给服务器写一个结束标记

c410b5c31d8a6a40f5de87044f9f193d.png

ace1ac85a4a5ca985593a86b2a06adc2.pngpublic static void main(String[] args) throws IOException {

//Step1:本地流读取文件

FileInputStream fis = new FileInputStream("E:\\A JI\\program\\java\\学习路线.png");

FileOutputStream fos = new FileOutputStream("E:\\A JI\\program\\java\\学习路线12.png");

//Step2:创建Socket对象,绑定服务器的端口号和IP地址

Socket socket = new Socket("127.0.0.1", 8888);

//Step3:获取网络字节输出流OutputStream对象

OutputStream os = socket.getOutputStream();

//Step4:本地字节输入流FileInputStream对象的read,读取本地文件

int len = 0;

byte[] bytes = new byte[1024];

while((len = fis.read(bytes)) != -1) {

//Step5:使用网络字节输出流OutputStream对象的write方法,上传到服务器

os.write(bytes, 0, len);

}

//防止阻塞状态

socket.shutdownOutput();

//Step6:Socket方法getInputStream,获取网络字节输入流InputStream对象

InputStream is = socket.getInputStream();

//Step7:网络字节输入流InputStream对象中read方法读取服务器回写数据

while((len = is.read(bytes)) != -1) {

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

//从服务器接收的数据放置文件中

fos.write(bytes);

}

//Step8:释放资源

fis.close();

socket.close();

}命名优化

服务器端

633db129a1523ee84fb2571689415627.png循环接收

让服务器一直处于监听状态

死循环 accept方法

并且服务器不关闭,ServerSocket.close不执行public static void main(String[] args) throws IOException {

//Step1

ServerSocket ss = new ServerSocket(8888);

//Step2

while (true) {

Socket socket = ss.accept();

//Step3

InputStream is = socket.getInputStream();

//Step4

File file = new File("E:\\A JI\\program\\java\\test-txt");

if (!file.exists()) {

file.mkdir();

}

/*自定义文件命名规则:防止同名的文件被覆盖

规则:域名+毫秒值+随机数

*/

String fileName = "itcast" + System.currentTimeMillis() +

new Random().nextInt(9999) + ".jpg";

//Step5

FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);

//Step6

int len = 0;

byte[] bytes = new byte[1024];

while((len = is.read(bytes)) != -1) {

//Step7

fos.write(bytes, 0, len);

}

//Step8、Step9

OutputStream os = socket.getOutputStream();

os.write("上传成功".getBytes());

fos.close();

socket.close();

}

//服务器就不用关闭了

//ss.close();

}多线程效率优化

一个客户端上传文件,开启一个线程,完成文件的上传

注意:run方法定义时,没有抛出异常,所以重写的时候也不能有,故将文件上传的程序放入try...catch中public class Test1Server {

public static void main(String[] args) throws IOException {

//Step1

ServerSocket ss = new ServerSocket(8888);

//Step2

while (true) {

Socket socket = ss.accept();

new Thread(new Runnable() {

@Override

public void run() {

try {

//Step3

InputStream is = socket.getInputStream();

//Step4

File file = new File("E:\\A JI\\program\\java\\test-txt");

if (!file.exists()) {

file.mkdir();

}

/*自定义文件命名规则:防止同名的文件被覆盖

规则:域名+毫秒值+随机数

*/

String fileName = "itcast" + System.currentTimeMillis() +

new Random().nextInt(9999) + ".jpg";

//Step5

FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);

//Step6

int len = 0;

byte[] bytes = new byte[1024];

while ((len = is.read(bytes)) != -1) {

//Step7

fos.write(bytes, 0, len);

}

//Step8、Step9

OutputStream os = socket.getOutputStream();

os.write("上传成功".getBytes());

fos.close();

socket.close();

} catch (IOException e) {

System.out.println(e);

}

}

}).start();

}

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值