计算机网络编程

网络编程

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机, Java 仍是企业和开发人员的首选开发平台。
  

课程内容的介绍

1. 计算机网络基础
2. Socket ServerSocket
3. TCP Socket 通信模型
4. UDP 编程

一、计算机网络基础

1.什么是计算机网络
把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大 、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息,共享硬件、软件、数据信息等资源。

2.了解网络通信协议
2.1.网络通信协议
要使计算机连成的网络能够互通信息,需要对数据传输速率、传输代码、代码结构、传输控制步骤、出错控制等制定一组标准,这一组共同遵守的通信标准就是网络通信协议,不同的计算机之间必须使用相同的通讯协议才能进行通信。

2.2 常见的网络通信协议
TCP/IP, 使用最为广泛的通讯协议。
TCP/IP 是英文 Transmission Control Protocol/Internet Protocol 的缩写,意思是 传输控制协议 / 网际协议”

2.2.1三次握手
TCP 协议建立连接需要三次会话 ( 握手 )

1. 第一次握手,客户端连接服务器。
2. 第二次握手,服务器接收了客户端的连接请求,服务器发送给客户端的确认消息。
3. 第三次握手,客户端获取到了服务器的确认信息,知道了服务已经知道我要连接他了,但是服务器还不知道客户端已经知道了,所以客户端发送给服务器消息说我们已经接受到了你的确认信息。
经过这三次握手,那么客户端和服务器都知道了要连接。
  
2.2.2四次挥手
TCP 协议中如果客户端要断开连接那么需要进行四次挥手操作。

1. 第一次,客户端发送请求关闭的消息给服务器。
2. 第二次,服务器接受到了客户端的消息,服务器发送消息给客户端确认(我收到了你的关闭请求,但是我数据还没有传完,等我传会告诉你的)。
3. 第三次,服务器给客户端要传输的数据以及传完了,服务器发送消息给客户端数据传完了,客户端你可以断开连接了。
4. 第四次,客户端发送消息给服务器,我要断开了,你也断开吧。
  
3.IP和端口号
3.1 什么是IP
网络中每台计算机的一个标识号,是一个逻辑地址, 127.0.0.1 localhost 代表本机地址。
IP 地址由四段组成,每个字段是一个字节, 8 位,最大值是 255 ,IP地址由两部分组成,即 网络地址 主机地址 。网络地址表示其属于互联网的哪一个网络,主机地址表示其属于该网络中的哪一台主机。二者是主从关系。IP 地址的四大类型标识的是网络中的某台主机。IPv4的地址长度为 32 位,共 4 个字节,但实际中我们用 点分十进制 记法。 192.168.1.1
   
3.2 分类
IP 地址根据网络号和主机号来分,分为 A B C 三类及特殊地址 D E 0 和全 1 的都保留不用。
A (1.0.0.0-126.0.0.0) (默认子网掩码: 255.0.0.0 0xFF000000 )第一个字节为网络号,后三个字节为主机号。该类IP 地址的最前面为 “0” ,所以地址的网络号取值于 1~126 之间。一般用于大型网络。
B (128.0.0.0-191.255.0.0) (默认子网掩码: 255.255.0.0 0xFFFF0000 )前两个字节为网络号,后两个字节为主机号。该类IP 地址的最前面为 “10” ,所以地址的网络号取值于 128~191 之间。一般用于中等规模网络。
C (192.0.0.0-223.255.255.0) (子网掩码: 255.255.255.0 0xFFFFFF00 )前三个字节为网络号,最后一个字节为主机号。该类IP 地址的最前面为 “110” ,所以地址的网络号取值于 192~223 之间。一般用于小型网络。
D :是多播地址。该类 IP 地址的最前面为 “1110” ,所以地址的网络号取值于 224~239 之间。一般用于多路广播用户[1]
E :是保留地址。该类 IP 地址的最前面为 “1111” ,所以地址的网络号取值于 240~255 之间。
  

Java 中对 IP 的操作。
package com.bobo.ip;import java.net.InetAddress;public class IpDemo01 {/*** Java中对IP的封装操作* @param args*/public static void main(String[] args) throws Exception {System.out.println(InetAddress.getLocalHost());System.out.println(InetAddress.getByName("127.0.0.1"));}
}
科普:为什么局域网中的 ip 地址都是 192.168 开头的?
私有地址
A 类地址: 10.0.0.0 - 10.255.255.255
B 类地址: 172.16.0.0 - 172.31.255.255
C 类地址: 192.168.0.0 - 192.168.255.255
    

3.3 IPv4IPv6
目前的全球因特网所采用的协议族是TCP/IP协议族。IP是TCP/IP协议族中网络层的协议,是TCP/IP协议族的核心协议。目前IP协议的版本号是4(简称为IPv4),发展至今已经使用了30多年。
IPv4的地址位数为32位,也就是最多有2的32次方的电脑可以联到Internet上。
近十年来由于互联网的蓬勃发展,IP位址的需求量愈来愈大,使得IP位址的发放愈趋严格,各项资料显示全球IPv4位址可能在2005至2008年间全部发完。
  
什么是IPv6?
IPv6是下一版本的互联网协议,也可以说是下一代互联网的协议,它的提出最初是因为随着互联网的迅速发展,IPv4定义的有限地址空间将被耗尽,地址空间的不足必将妨碍互联网的进一步发展。
为了扩大地址空间,拟通过IPv6重新定义地址空间。IPv6采用128位地址长度,几乎可以不受限地提供地址。按保守方法估算IPv6实际可分配的地址,整个地球的每平方米面积上仍可分配1000多个地址。在IPv6的设计过程中除了一劳永逸地解决了地址短缺问题以外,还考虑了在IPv4中解决不好的其它问题,主要有端到端IP连接、服务质量(QoS)、安全性、多播、移动性、即插即用等。
  
IPv6与IPv4相比有什么特点和优点?
更大的地址空间。IPv4中规定IP地址长度为32,即有2^32-1个地址;而IPv6中IP地址的长度为128,即有2^128-1个地址。
更小的路由表。IPv6的地址分配一开始就遵循聚类(Aggregation)的原则,这使得路由器能在路由表中用一条记录(Entry)表示一片子网,大大减小了路由器中路由表的长度,提高了路由器转发数据包的速度。
增强的组播(Multicast)支持以及对流的支持(Flow-control)。这使得网络上的多媒体应用有了长足发展的机会,为服务质量(QoS)控制提供了良好的网络平台。
加入了对自动配置(Auto-configuration)的支持。这是对DHCP协议的改进和扩展,使得网络(尤其是局域网)的管理更加方便和快捷。
更高的安全性.在使用IPv6网络中用户可以对网络层的数据进行加密并对IP报文进行校验,这极大的增强了网络安全。
3.4 端口号
具有网络功能的应用软件的标识号。
特点:
1. 端口是一个软件结构,被客户程序或服务程序用来发送和接收数据,一台服务器有 256*256 个端口。
2. 0-1023 是公认端口号,即已经公认定义或为将要公认定义的软件保留的。
3. 1024-65535 是并没有公共定义的端口号,用户可以自己定义这些端口的作用。
4. 端口与协议有关: TCP UDP 的端口互不相干。
  

二、网络通信

1.SocketServerSocket
1.1 什么是Socket
两个应用程序可以通过一个双向的网络通信连接实现数据的交换,这个双向的链路的一端我们称为一个Socket
  
1.2 Socket案例
1.2.1 基本连接操作
   
服务端的创建
package com.bobo.socket01;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** Socket的第一个案例** @param args*/public static void main(String[] args) {try {// 创建一个ServerScoket对象  如果服务器关闭了,那么我们是连接不上的ServerSocket ss = new ServerSocket(8888);System.out.println("服务器启动了....");// 接受客户端的访问while(true){Socket s = ss.accept(); // 这是一个阻塞的方法,等待客户端的访问。System.out.println(s.getInetAddress().getHostAddress() + " : 客户端来访问了");s.close();}} catch (IOException e) {e.printStackTrace();}}
}
客户端的创建
package com.bobo.socket01;import java.net.Socket;
import java.rmi.server.ExportException;public class TestClientSocket {/*** Socket 客户端程序* @param args*/public static void main(String[] args) {try{// 127.0.0.1 / localhost 表示的当前的主机// 获取一个Socket对象 指定要访问的服务器 ip+端口 可以定位到要访问的是哪台计算机上的服务Socket socket = new Socket("192.168.8.71",8888);System.out.println("客户端开始链接了...");socket.close();}catch (Exception e){e.printStackTrace();}}
}
当前计算机的描述
1. 127.0.0.1
2. localhost
3. 当前电脑分配的 IP(192.168.8.71)
  
1.2.2 客户端发送消息给服务器
通过字节输入输出流实现。
  
服务端代码
package com.bobo.socket02;import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端 接收客户端的消息* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(8899);while(true){// 等待获取客户端的连接Socket s = ss.accept();System.out.println(s.getInetAddress().getHostAddress()+"连接了...");// 获取一个字节输入流,获取客户端传递的信息InputStream inputStream = s.getInputStream();byte[] b = new byte[1024];int num = 0 ;while((num = inputStream.read(b)) != -1){System.out.println(new String(b,0,num));}// 关闭相关的资源inputStream.close();s.close();}}catch (Exception e){e.printStackTrace();}}
}
客户端代码
package com.bobo.socket02;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class TestClientSocket {/*** 客户端*    发送消息到服务器* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",8899);// 通过socket对象获取一个字节输出流OutputStream outputStream = socket.getOutputStream();outputStream.write("服务器,你好啊,我是XXXXX".getBytes());outputStream.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
效果:

用缓冲流来操作。
  
服务端:
package com.bobo.socket03;import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端 接收客户端的消息* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(8899);while(true){// 等待获取客户端的连接Socket s = ss.accept();System.out.println(s.getInetAddress().getHostAddress()+"连接了...");BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));System.out.println(bufferedReader.readLine());bufferedReader.close();s.close();}}catch (Exception e){e.printStackTrace();}}
}
客户端代码
package com.bobo.socket03;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;public class TestClientSocket {/*** 客户端*    发送消息到服务器* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",8899);// 通过socket对象获取一个字节输出流BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bufferedWriter.write("哈哈哈哈哈....");bufferedWriter.newLine(); // 必须要显示的调用bufferedWriter.flush();bufferedWriter.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
输出效果

1.2.3 服务端发送消息给客户端
服务端代码:
package com.bobo.socket04;import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端*    发送消息给客户端* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(8989);while(true){Socket s = ss.accept();System.out.println(s.getInetAddress().getHostAddress()+" 连接了");// 服务器发送消息给客户端BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));bufferedWriter.write(s.getInetAddress().getHostAddress()+" 你好啊,你的连接我已经收到了");bufferedWriter.newLine();bufferedWriter.flush();bufferedWriter.close();s.close();}} catch (IOException e) {e.printStackTrace();}}
}
客户端代码
package com.bobo.socket04;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;public class TestClientSocket {/*** 客户端 接收服务的消息* @param args*/public static void main(String[] args) {try {Socket s  = new Socket("localhost",8989);System.out.println("客户端启动了...");BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));System.out.println(bufferedReader.readLine());bufferedReader.close();s.close();} catch (IOException e) {e.printStackTrace();}}
}
输出结果:

1.2.4 课堂案例
客户端接收键盘输入信息,然后将该信息发送给服务器,服务器读取客户端发送来的信息。
    
服务端代码
package com.bobo.socket05;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端*     接收客户端的消息* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(9999);while(true){Socket s = ss.accept();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s.getInputStream()));System.out.println(s.getInetAddress().getHostAddress()+":"+bufferedReader.readLine());bufferedReader.close();s.close();}} catch (IOException e) {e.printStackTrace();}}
}
客户端代码
package com.bobo.socket05;import java.io.*;
import java.net.Socket;public class TestClientSocket {/*** 客户端接收键盘输入信息,然后将该信息发送给服务器,服务器读取客户端发送来的信息* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",9999);System.out.println("客户端启动了,请输入要发送的消息:");// 接收键盘输入BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));// 客户端发送消息BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bufferedWriter.write(bufferedReader.readLine());bufferedWriter.newLine();bufferedWriter.flush();bufferedWriter.close();bufferedReader.close();socket.close();} catch (IOException e) {e.printStackTrace();}}
}
效果

1.2.5 一对一聊天实现
实现一个客户端发送消息给服务器,然后服务器获取到消息后再返还消息给客户端,一对一通信的效果。
    
服务端代码:
package com.bobo.socket06;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(8080);while(true){Socket s = ss.accept();// 服务端通过键盘录入的方式 返回消息给客户端BufferedReader input = new BufferedReader(new InputStreamReader(System.in));// 读取客户端传递的消息BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));// 返回消息给客户端BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));// 实现频繁读取写入的效果while(true){System.out.println(s.getInetAddress().getHostAddress()+":" + br.readLine()) ;// 返回信息给客户端qbw.write(input.readLine());bw.newLine();bw.flush();}}} catch (IOException e) {e.printStackTrace();}}
}
客户端代码:
package com.bobo.socket06;import java.io.*;
import java.net.Socket;public class TestClientSocket {/*** 客户端*    实现和服务器一对一的聊天** @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",8080);// 接收键盘输入BufferedReader input = new BufferedReader(new InputStreamReader(System.in));// 读取信息BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));// 写入信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));while(true){bw.write(input.readLine());bw.newLine();bw.flush();System.out.println("服务器说:" + br.readLine());}} catch (IOException e) {e.printStackTrace();}}
}
效果:

效果虽然是实现了,但是总的体验还是不是很好,因为是在读写在一个线程中,就造成了读写操作的阻塞。
1.2.6 自由聊天的实现
在上面的案例中客户端和服务器的读写操作同一个线程中进行的,所以会造成消息的阻塞,那么我们可以结合前面讲过的多线程的知识来解决当前的问题。将读的操作交给一个线程,将写的操作交给一个线程,那么读写之间就没有阻塞现象了。具体实现如下:
    
读操作的线程:
package com.bobo.socket07.thread;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;/*** 专门用来负责读取数据的线程*     线程只需要获取到对应的Socket对象*     就可以获取Socket中的数据及向Socket中写入数据*/
public class ReadSocketThread implements Runnable{private Socket socket;public ReadSocketThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));while(true){String str = br.readLine();System.out.println(str);}} catch (IOException e) {e.printStackTrace();}}
}
写操作的线程
package com.bobo.socket07.thread;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;/*** 专门用来发送数据的线程*/
public class WriterSocketThread implements Runnable {private Socket socket;public WriterSocketThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try{// 获取键盘数据BufferedReader input = new BufferedReader(new InputStreamReader(System.in));// 输出信息BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));while(true){String str = input.readLine();bw.write(str);bw.newLine();bw.flush();}}catch (Exception e){}}
}
服务端代码
package com.bobo.socket07;import com.bobo.socket07.thread.ReadSocketThread;
import com.bobo.socket07.thread.WriterSocketThread;import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务器*    客户端和服务器实现自由聊天* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(7891);while(true){Socket s = ss.accept();// 读客户端数据和写客户端数据都交给子线程去处理// 读取数据的线程new Thread(new ReadSocketThread(s)).start();// 写入数据的线程new Thread(new WriterSocketThread(s)).start();// 读写操作分别交给两个不同的线程来处理,就不会出现 读取必须要等待输入完成后再执行的情况}} catch (IOException e) {e.printStackTrace();}}
}
客户端代码
package com.bobo.socket07;import com.bobo.socket07.thread.ReadSocketThread;
import com.bobo.socket07.thread.WriterSocketThread;import java.io.IOException;
import java.net.Socket;public class TestClientSocket {/*** 实现客户端和服务自由聊天* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",7891);// 读取数据的线程new Thread(new ReadSocketThread(socket)).start();new Thread(new WriterSocketThread(socket)).start();} catch (IOException e) {e.printStackTrace();}}
}
效果

1.2.7 有退出的自由聊天
上面的案例除了显示的把服务关掉之外程序会一直运行,那么如果我们要显示的断开聊天,我们只需要在读写线程中添加断开的逻辑即可。
    
读取数据的线程
package com.bobo.socket08.thread;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;public class ReadSocketThread implements Runnable{private Socket socket;public ReadSocketThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));while(true){String str = br.readLine();System.out.println(socket.getInetAddress().getHostAddress()+":" + str);// 添加退出聊天的逻辑if("exit".equals(str)){ // 表示退出System.out.println(socket.getInetAddress().getHostAddress()+"退出了...");br.close();break; // 结束循环,终止线程}}} catch (IOException e) {e.printStackTrace();}}
}
写入数据的线程
package com.bobo.socket08.thread;import java.io.*;
import java.net.Socket;public class WriterSocketThread implements Runnable{private Socket socket;public WriterSocketThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {BufferedReader input = new BufferedReader(new InputStreamReader(System.in));BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));while(true){String str = input.readLine();bw.write(str);bw.newLine();bw.flush();// 如果我发送的是 exit 的话,那么读到这个信息的 会退出,此时发送也应该要退出if("exit".equals(str)){// 读取数据的线程也要退出System.out.println(socket.getInetAddress().getHostAddress()+"退出了");bw.close();input.close();break;}}} catch (IOException e) {e.printStackTrace();}}
}

三、TCP Socket 通信模型

1.通信原理

2.课堂案例
实现 TCP 通信模型实现客户端 1 1 的通信,实现案例。
读写的线程和上面案例是一样的,就不再复制了。
    
客户端代码
package com.bobo.socket09;import com.bobo.socket09.thread.ReadSocketThread;
import com.bobo.socket09.thread.WriterSocketThread;import java.io.IOException;
import java.net.Socket;public class TestClientSocket {/*** 实现客户端对客户端的一对一聊天* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",7799);new Thread(new ReadSocketThread(socket)).start(); // 启动读取信息的线程new Thread(new WriterSocketThread(socket)).start();} catch (IOException e) {e.printStackTrace();}}
}
服务器代码
package com.bobo.socket09;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;public class TestServerSocket {/*** ServerSocket*    模拟客户端和客户端一对一的聊天* @param args*/public static void main(String[] args) {// 记录以及建立连接的SocketList<Socket> list = new ArrayList<>();try {ServerSocket ss = new ServerSocket(7799);for(int i = 0 ; i < 2 ; i++){Socket s = ss.accept();// 客户端建立连接后 将连接对应的Socket对象保存起来list.add(s);}// 第一个Socket接收到信息之后 应该将信息在第二个Socket中输出// 第二个Socket接收到信息之后 应该将信息在第一个Socket中输出new Thread(new ServerThread(list.get(0),list.get(1))).start();new Thread(new ServerThread(list.get(1),list.get(0))).start();} catch (IOException e) {e.printStackTrace();}}
}/*** ServerSocket端的线程*   专门处理信息的中转*/
class ServerThread implements  Runnable{private Socket s1 ; // 发送者private Socket s2 ; // 接收者public ServerThread(Socket s1, Socket s2) {this.s1 = s1;this.s2 = s2;}@Overridepublic void run() {try {while(true){BufferedReader br = new BufferedReader(new InputStreamReader(s1.getInputStream()));// 获取 发送者发送的消息String str = br.readLine();// 将消息转发给另一个客户端BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s2.getOutputStream()));bw.write(str);bw.newLine();bw.flush();}} catch (IOException e) {e.printStackTrace();}}
}
IDEA 中默认是不支持同一个主方法执行多次的,要并发执行需要如下设置。

3.文件上传下载
文件上传:客户端将 File 传输给服务器, File 会保存在服务中。
文件下载:客户端从服务器获取 File
   
第一种实现的方式:
package com.bobo.socket10;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** ServerSocket*    接收客户端传递的文件* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(9999);while(true){Socket s = ss.accept();// 读取文件BufferedInputStream bi = new BufferedInputStream(s.getInputStream());// 将上传的文件保存到服务指定的位置BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream("D:/aaa.txt"));// 又是一个文件复制byte[] b = new byte[1024*1024];int num = 0;while((num = bi.read(b)) != -1){bo.write(b,0,num);}bi.close();bo.close();}} catch (IOException e) {e.printStackTrace();}}
}
package com.bobo.socket10;import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;public class TestClientSocket {/*** Client*    发送文件到服务器中  上传操作* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",9999);// 先读取某个文件BufferedInputStream bi = new BufferedInputStream(new FileInputStream("d:/IO/1.mp4"));// 将读取的文件写入到Socket中BufferedOutputStream bo = new BufferedOutputStream(socket.getOutputStream());// 文件的复制byte[] b = new byte[1024*1024];int num = 0 ;//bo.write("1.mp4".getBytes());while((num = bi.read(b)) != -1){bo.write(b,0,num);}bo.close();bi.close();} catch (IOException e) {e.printStackTrace();}}
}
这种实现方式我们发现服务端可以获取到客户端传递的数据,但是并不清楚传递的是什么类型的数据,名称叫什么也不知道,所以处理起来比较麻烦。
package com.bobo.socket11;import java.io.*;
import java.net.Socket;public class TestClientSocket {/*** 客户端* @param args*/public static void main(String[] args) {try {Socket socket = new Socket("localhost",9988);File file = new File("d:/IO/1.mp4");// 读取文件BufferedInputStream bi = new BufferedInputStream(new FileInputStream(file));// 文件写入Socket ObjectOutputStreamObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());// 先写入文件名称oos.writeUTF(file.getName());oos.writeLong(file.length());// 文件的传输byte[] b = new byte[1024*1024];int num = 0;while((num = bi.read(b)) != -1){oos.write(b,0,num);}// 关闭资源oos.close();bi.close();} catch (IOException e) {e.printStackTrace();}}
}
package com.bobo.socket11;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;public class TestServerSocket {/*** 服务端* @param args*/public static void main(String[] args) {try {ServerSocket ss = new ServerSocket(9988);while(true){Socket s = ss.accept();// 读取文件 ObjectInputStreamObjectInputStream bis = new ObjectInputStream(s.getInputStream());// 获取文件名称String fileName = bis.readUTF();// 获取文件的大小long length = bis.readLong();System.out.println("文件名称:" + fileName + "文件大小:" + length);// 保存文件到服务器BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("d:/", fileName)));byte[] b = new byte[1024*1024];int num = 0;int i = 1 ;while((num = bis.read(b)) != -1){bos.write(b,0,num);System.out.println("保存的进入:" + (1024*1024*i)/length * 100 + "%" );i++;}bis.close();bos.close();}} catch (IOException e) {e.printStackTrace();}}
}

四、了解UDP

1.UDP协议
UDP(User Datagram Protocol) 用户数据报协议, UDP TCP 位于同一层 - 传输层,但它对于数据包的顺序错误或重发没有TCP 来的可靠。
TCP: 相当于打电话。
UDP: 相当于发电报。
  
UDP 是一种面向无连接的通信协议。

UDP 向应用程序提供了一种发送封装的原始 IP 数据报的方法,并且发送时无需建立连接,不保证可靠数据的传输。
    
2.TCP协议和UDP协议的差别

面向无连接的数据传输,不可靠的,但效率高。
一次发送的数据不能超过 64KB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/215712.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构基础介绍

一.起源及重要性 1968 年&#xff0c;美国的高德纳 Donakl E . Kn uth 教授在其所写的《 计算机程序艺术》第一卷《基本算法 》 中&#xff0c;较系统地阐述了数据的逻辑结构和存储结构及其操作&#xff0c; 开创了数据结构的课程体系 &#xff0c;数据结构作为一门独立的…

B029-JDBC增强

目录 PreparedStatement 查询1.sql注入2.Statement分析 (面试题)3.PreparedStatement (面试题) 登录功能的完善事务链接池概念实现DBCP连接池实现第一种配置方式第二种配置方式 返回主键BaseDao的抽取 PreparedStatement 查询 1.sql注入 就是在sql的字符串拼接的时候&#xf…

基于单片机的定时插座在智能家居中的应用

近年来&#xff0c;随着科学技术的发展迅速&#xff0c;人们对智能化的要求越来越高。越来越多的智能化产品进入千家万户&#xff0c;如电脑电视、扫地机器人、智能空气净化器等。这些家居电器和电子产品大都需要连接电源&#xff0c;为满足多种用电器的正常使用&#xff0c;延…

DevEco Studio 生成HPK文件

DevEco Studio 生成HPK文件 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、生成HPK文件 生成的HPK文件存放在entry文件夹下。下图是未生成HPK的样式。 生成HPK&#xff1a;菜单Build->Build Hap(s)/APP(s)->Build Hap(s)…

启动jar包命令

一、Windows环境 找到jar包的位置&#xff1b; 按shift键&#xff0c;点击鼠标右键&#xff0c;选中在此处打开PowerShell窗口&#xff1b; 此时进入命令行工具 输入java -jar .\java_web-0.0.1-SNAPSHOT.jar&#xff08;注意空格&#xff09;。 二、Linux环境 2.1 方式一 …

039.Python面向对象_三大特性综合案例2

我 的 个 人 主 页&#xff1a;&#x1f449;&#x1f449; 失心疯的个人主页 &#x1f448;&#x1f448; 入 门 教 程 推 荐 &#xff1a;&#x1f449;&#x1f449; Python零基础入门教程合集 &#x1f448;&#x1f448; 虚 拟 环 境 搭 建 &#xff1a;&#x1f449;&…

一、微前端目标、前端架构的前生今世、微前端架构优势和劣势、软件设计原则与分层

1、目标 2、前端架构的前世今生 ① 初始&#xff1a;无架构&#xff0c;前端代码内嵌到后端应用中 ② 后端 MVC 架构&#xff1a;将视图层、数据层、控制层做分离 缺点&#xff1a;重度依赖开发环境&#xff0c;代码混淆严重&#xff08;在调试时&#xff0c;需要启动后端所有…

小型洗衣机哪个牌子质量好?迷你洗衣机排名前十名

随着内衣洗衣机的流行&#xff0c;很多小伙伴在纠结该不该入手一款内衣洗衣机&#xff0c;专门来洗一些贴身衣物&#xff0c;答案是非常有必要的&#xff0c;因为我们现在市面上的大型洗衣机只能做清洁&#xff0c;无法对我们的贴身衣物进行一个高强度的清洁&#xff0c;而小小…

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分 概述NLP 简介文本处理词嵌入上下文理解 文本数据加载to_device 函数构造数据加载样本数量 len获取样本 getitem 分词构造函数调用函数轮次嵌入 RobertaRoberta 创新点NSP (Next Sentence Prediction…

23种设计模式之装饰者模式(被装饰者,接口层,装饰抽象层,具体装饰者)

23种设计模式之装饰者模式 文章目录 23种设计模式之装饰者模式设计思想装饰者模式的优点装饰者模式的缺点装饰者模式的优化方法UML 解析预设场景 代码释义总结 设计思想 原文:装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0…

应用在LED灯光控制触摸屏中的触摸芯片

LED灯光控制触摸屏方法&#xff0c;包括&#xff1a;建立触摸屏的触摸轨迹信息与LED灯光驱动程序的映射关系&#xff1b;检测用户施加在触摸屏上的触摸轨迹&#xff0c;生成触摸轨迹信息&#xff1b;根据生成的触摸轨迹信息&#xff0c;调用对应的LED灯光驱动程序&#xff0c;控…

智能优化算法应用:基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于头脑风暴算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.头脑风暴算法4.实验参数设定5.算法结果6.…

智能优化算法应用:基于蝙蝠算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝙蝠算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝙蝠算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝙蝠算法4.实验参数设定5.算法结果6.参考文献7.MA…

酷开科技多维度赋能营销,实力斩获三项大奖

在数智化新阶段、广告新生态、传播新业态的背景下&#xff0c;“第30届中国国际广告节广告主盛典暨网易传媒态度营销峰会”于11月18日在厦门国际会展中心盛大举行。来自全国的品牌方、战略决策者、媒体平台和品牌服务机构等汇聚一堂。在50000&#xff0b;现场观众和数千万线上观…

vue elementui点击按钮新增输入框(点多少次就新增多少个输入框,无限新增)

效果如图&#xff1a; 核心代码&#xff1a; <div v-for"(item,index) in arrayData" :key"item.id">//上面这个是关键代码&#xff0c;所有思路靠这个打通<el-inputtype"input" //除了输入框&#xff0c;还有textarea等placeholder&…

k8s详细教程(一)

—————————————————————————————————————————————— 博主介绍&#xff1a;Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 &#x1f345;文末获取源码…

《Spring Cloud Alibaba 从入门到实战》分布式消息(事件)驱动

分布式消息&#xff08;事件&#xff09;驱动 1、简介 事件驱动架构(Event-driven 架构&#xff0c;简称 EDA)是软件设计领域内的一套程序设计模型。 这套模型的意义是所有的操作通过事件的发送/接收来完成。 传统软件设计 举个例子&#xff0c;比如一个订单的创建在传统软…

「差生文具多系列」推荐两个好看的 Redis 客户端

&#x1f4e2; 声明&#xff1a; &#x1f344; 大家好&#xff0c;我是风筝 &#x1f30d; 作者主页&#xff1a;【古时的风筝CSDN主页】。 ⚠️ 本文目的为个人学习记录及知识分享。如果有什么不正确、不严谨的地方请及时指正&#xff0c;不胜感激。 直达博主&#xff1a;「…

Fabric使用自己的链码进行测试-go语言

书接前文 Fabric链码部署-go语言 通过上面这篇文章&#xff0c;你可以部署好自己的链码 &#xff08;后面很多命令是否需要修改&#xff0c;都是根据上面这篇文章来的&#xff0c;如果零基础的话建议先看上面这篇&#xff09; 就进行下一步 在测试网络上运行自己的链码 目…

PDF文件的限制编辑,如何设置?

想要给PDF文件设置一个密码防止他人对文件进行编辑&#xff0c;那么我们可以对PDF文件设置限制编辑&#xff0c;设置方法很简单&#xff0c;我们在PDF编辑器中点击文件 – 属性 – 安全&#xff0c;在权限下拉框中选中【密码保护】 然后在密码保护界面中&#xff0c;我们勾选【…