1、计算机网络
计算机网络是指将地理位置不同
的具有独立功能的多台计算机
及其外部设备,通过通信线路连接
起来实现资源共享和信息传递的计算机系统
。
- 互联网:(Inter)点与点相连;能进入互联网的都是点;
- 万维网:(WWW-World Wide Web)端与端相连;移动端、服务端、虚拟主机;
- 物联网:(IoT-Internet of things)物与物相连;
- 网络编程:让计算机与计算机之间建立连接、进行通信;
2、网络模型
网络模型就是研究计算机网络之间以何种规则进行通信的问题。
2-1、OSI 模型
OSI(Open System Interconnect),即开放式系统互联。 一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互连模型。
ISO为了更好的使网络应用更为普及,推出了OSI参考模型。其含义就是推荐所有公司使用这个规范来控制网络。这样所有公司都有相同的规范,就能互联了。
OSI定义了网络互连的七层框架,分别是:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。
2-2、 TCP/IP模型
一组用于实现网络互联的通讯协议,协议分为四层。
3、网络编程三要素
网络编程三要素是IP地址
、端口号
、协议
;
3-1、IP地址
IP协议:Internet Protocol Address互联网协议地址/网际协议地址;分配给互联网设备的数字标签(唯一标识)。
IP地址有两种
IPV4:
- 4字节32位整数,分为4段8位二进制数,每8位之间用原点隔开,每8位整数可转换为一个0~255的十进制整数;255.255.255.255
IPV6:
- 16字节128位整数,分为8段十六进制数,每16位之间用原点隔开,每16位整数可转换为一个0~65535的十进制数;
IPV4的应用分类:
3-2、端口号
端口号:在通信实体上进行网络通信的程序的唯一标识;计算机上的一个程序的进程。不同端进程有不同的端口,用来区分软件。
端口号分类:
- 公认端口:0~1023
- 注册端口:1024~49151
- 动态或者私有端口:49152~65535
常用端口:
- MySQL:3306
- Oracle:1521
- Tomcat:8080
- SMTP:25
- http:80
- Https:443
- FTP:21
- Telent:23
- FTP服务器:21
常用终端命令:
- netstat -ano # 查看所有的端口
- netstat -ano | findstr “5900” # 查看指定的端口
- tasklist | findstr “8696” # 查看指定端口的进程
3-3、协议
协议一般分为TCP协议(连接,稳定,例如:打电话)
和UDP协议(不连接,不稳定,例如:发信息)
。
User Datagram Protocol用户数据报协议,简称
UDP协议
,将数据源和目的封装成数据包中;
- 一种无需连接的传输层协议;
- 每个数据报的大小在限制在64k;
- 无连接是不可靠协议,不需要建立连接速度快;
- 提供面向事务的简单不可靠的信息传送服务;
Transmission Control Protocol传输控制协议,简称
TCP协议
,建立连接形成传输数据的通道;
- 一种面向连接的、可靠的、基于字节流的传输层通讯协议;
- 数据的大小无限制,越大越慢;
- 建立连接时需三次握手(success),断开连接时需四次挥手;
- 必须建立连接效率会稍低;
4、InetAddress类
此类表示Internet协议(IP)地址,封装了与该IP地址相关的所有信息,并提供获取信息的常用方法。
- public static InetAddress getLocalHost():获得本地主机地址对象
- public static InetAddress getByName(String host):通过主机名称获取ip地址对象
- public static InetAddress[] getAllByName(String host):获取所有相关的地址对象
- public String getHostAddress(): 返回ip的字符串形式(文本形式)
- public String getHostName():获取ip地址的主机名称
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//通过主机名获取ip地址对象
//InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
InetAddress inetAddress = InetAddress.getLocalHost();
//返回ip的字符串形式(文本形式)
String ip = inetAddress.getHostAddress();
//获取ip地址的主机名称
String name = inetAddress.getHostName();
System.out.println(ip + "\t" + name);
}
}
5、Socket套接字
Socket(套接字:两台机器间通信的端点)是网络中的一个通讯节点;通信要求:IP地址+端口号,客户端套接字Socket与服务器套接字ServerSocket;
Socket原理
- 通信的两端都有Socket
- 网络通信其实就是Socket间的通信
- 数据在两个Socket间通过IO流传输
6、UDP传输
建立发送端,接收端;属于不可靠连接,建立数据报包,调用Socket的发送接收的方法;
DatagramSocket与DatagramPacket
6-1、UDP接收端
接收步骤:
- 创建Socket套接字对象 DatagramSocket(int port)
- 创建数据报包(接收容器)接收数据DatagramPacket(byte[] buf, int length)
- 接收数据报包中的实际数据 receive(DatagramPacket p)
- 将发送数据的信息解析出来 (解析的实际发送端数据)
- 展示数据
- 关闭资源
- public DatagramSocket(int port) :绑定端口
- public DatagramPacket(byte[] buf, int length)
参数1:自定义的缓冲区
参数2:自定义缓冲大小的长度- public void receive(DatagramPacket p):接收数据报包中的实际数据
- DatagramPacket:数据报包中 public byte[] getData():获取实际缓冲区
- public int getLength() :获取数据的实际长度
- public InetAddress getAddress() :将IP地址解析出来
- InetAddress 里面的getHostAddress()中IP是字符串形式
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//创建Socket套接字对象,绑定端口
DatagramSocket ds = new DatagramSocket(10086);
//创建数据包接收数据
byte[] bytes = new byte[1024];
int length = bytes.length;
DatagramPacket dp = new DatagramPacket(bytes, length);
//阻塞接收数据,因为要等待发送端的连接
ds.receive(dp);
//将发送的数据信息解析出来
byte[] bytes2 = dp.getData();
int length2 = dp.getLength();
String s = new String(bytes2,0,length2);
//解析ip
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
System.out.println("发送端的ip地址是:"+ip+",发送的数据是:"+s);
//关闭资源
ds.close();
}
}
6-2、UDP发送端
发送步骤:
- 创建一个Socket套接字对象DatagramSocket()
- 创建数据报包对象(DatagramPacket) :包含:数据信息,包含ip地址,包含端口
- 使用DatagramSocket套接字对象发送数据报包
- 关闭资源
- public DatagramPacket(byte[] buf, int length, InetAddress address,int port):创建数据报包对象(DatagramPacket) :包含:数据信息,包含ip地址,包含端口
- public void send(DatagramPacket p):使用DatagramSocket套接字对象发送数据报包
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建一个Socket对象
DatagramSocket ds = new DatagramSocket();
//实际字节数组:存储需要被发送的内容
byte[] bytes = "你好!".getBytes();
//实际长度
int length = bytes.length;
//ip地址对象
InetAddress inetAddress = InetAddress.getByName("10.12.151.138");
//定义端口号
int port = 10086;
//创建数据报包
DatagramPacket dp = new DatagramPacket(bytes, length, inetAddress, port);
//使用DatagramSocket套接字对象发送数据报包
ds.send(dp);
// 4)关闭资源
ds.close();
}
}
- 先开启接收端,在发送数据
- 接收端不要运行多次:否则就出现:java.net.BindException: Address already in use: Cannot bind 端口号冲突
6-3、代码优化(一步实现)
//发送端
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建DatagramSocket
DatagramSocket ds = new DatagramSocket();
//创建数据包对象
byte[] bytes = "nihao!".getBytes();
DatagramPacket dp = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("10.12.151.138"),10086);
//发送数据
ds.send(dp);
//关闭资源
ds.close();
}
}
//接收端
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//创建DatagramSocket
DatagramSocket ds = new DatagramSocket(10086) ;
//创建数据报包:接收容器
byte[] bytes = new byte[1024] ;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length) ;
//3)接收
ds.receive(dp);
//解析数据
String s = new String(dp.getData(),0,dp.getLength()) ;
//获取ip地址
String ip = dp.getAddress().getHostAddress() ;
System.out.println("IP:"+ip+"发送的内容是:"+s);
//关闭资源
ds.close();
}
}
6-4、案例_无限发送
需求:
- 发送端发送数改为"键盘录入"使用BufferedReader流的方式,
- 自定义一个结束条件"byt bye /886"
- 接收端不断的去接收消息不关闭
//发送端
public class DemoSend {
public static void main(String[] args) throws IOException {
//创建发送端的DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//发送端不断的键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine())!= null){
if("886".equals(line)){
break;
}
//创建数据报包对象
byte[] bytes = line.getBytes();
DatagramPacket dp = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("10.12.151.138"),10086);
//发送数据
ds.send(dp);
}
//关闭资源
ds.close();
}
}
//接收端
public class DemoReceived {
public static void main(String[] args) throws IOException {
//创建接收的socket对象
DatagramSocket ds = new DatagramSocket(10086);
while(true){
//创建数据接收包,接收容器
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
//接收数据
ds.receive(dp);
//解析数据
String s = new String(dp.getData(),0,dp.getLength());
//解析IP
String ip = dp.getAddress().getHostAddress();
System.err.println("from:"+ip +"data is :" +s);
}
}
}
6-5、案例_多线程同一窗口
需求:
将UDP协议 发送端和接收端 在一个窗口下进行聊天
步骤:
- 开启两个子线程:分别实现Runnable接口并且重写run方法
- sendDemo:发送端
- ReceiveDemo:接收端
- 开启两个子线程 :Thread(Runnable target)
//接收端
public class ReceiveDemo implements Runnable{
private DatagramSocket ds ;
public ReceiveDemo(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 s = new String(dp.getData(),0,dp.getLength()) ;
String ip = dp.getAddress().getHostAddress();
System.out.println("ip is:"+ip+"data is:"+s);
}
} catch (IOException e) {
e.printStackTrace();
}
//接收端模拟真实场景,不需要关闭
}
}
//发送端
public class SendDemo implements Runnable {
private DatagramSocket ds ;
public SendDemo(DatagramSocket ds) {
this.ds = ds ;
}
@Override
public void run() {
//键盘录入数据
try {
BufferedReader br = new BufferedReader(
new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null) {
//自定义结束条件
if("886".equals(line)) {
break ;
}
//创建数据报包对象
byte[] bytes = line.getBytes() ;
DatagramPacket dp = new DatagramPacket(bytes, bytes.length,InetAddress.getByName("10.12.151.138"), 12345) ;
//发送数据
ds.send(dp);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//释放资源
if(ds!=null) {
ds.close();
}
}
}
}
//主方法
public class ChatRoom {
//主线程
public static void main(String[] args) {
try {
//创建一个DataSocket对象
DatagramSocket ds = new DatagramSocket() ;
DatagramSocket ds2 = new DatagramSocket(12345) ;
//创建发送端资源类对象
SendDemo sd = new SendDemo(ds) ;
//创建接收端资源类对象
ReceiveDemo rd = new ReceiveDemo(ds2);
Thread t1 = new Thread(sd) ;
Thread t2 = new Thread(rd) ;
//开启线程
t1.start();
t2.start();
} catch (SocketException e) {
e.printStackTrace();
}
}
}
7、TCP传输
建立客户端和服务器端,属于安全连接;建立连接后,通过Socket中的IO流进行数据的传输;
Socket和ServerSocket
7-1、TCP客户端
步骤:
- 创建Socket套接字对象 Socket(String host,int port)
- 获取连接通道内的字节输出流对象 public OutputStream getOutputStream()
- 通过该字节输出流对象写数据 write(byte[] bytes)
- 释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的流套接字对象
Socket socket = new Socket("10.12.151.138",10086);
//获取通道内的字节输出流对象
OutputStream out = socket.getOutputStream();
//写数据
out.write("你好Java".getBytes());
//关闭资源
socket.close();
}
}
7-2、TCP服务端
步骤:
- 创建ServerSocket套接字对象 ServerSocket(int port)
- 侦听客户端连接 public Socket accept() 阻塞式方法
- 获取通道内字节输入流对象 public InputStream getInputStream()
- 一次读取一个字节数组public int read(byte[] bytes)
- 展示数据 public InetAddress getInetAddress():获取ip地址对象
- 释放资源
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建ServerSocket服务套接字
ServerSocket ss = new ServerSocket(10086);
//监听客户端连接:阻塞式监听方法,会一直等待客户端连接成功后才不阻塞
//返回的就是当前客户端对象
Socket socket = ss.accept();
//获取通道内字节输入流对象
InputStream in = socket.getInputStream();
//读取通道流的数据
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String str = new String(bytes,0,len);
//展示数据
String ip = socket.getInetAddress().getHostAddress();
System.out.println("ip地址是:"+ip+",发送的数据是:"+str);
//关闭资源
ss.close();
}
}
7-3、案例_服务端反馈客户端
需求:客户端发消息服务端给出反馈
//客户端
public class ClientTest {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("10.12.151.138",11111);
//获取通过的内存输出流对象
OutputStream out = s.getOutputStream();
out.write("你好!".getBytes());
//客户端的接收服务器的反馈
//获取通道内的输入流对象
InputStream in = s.getInputStream();
//一次读取一个字节
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String serverMsg = new String(bytes,0,len);
System.out.println(serverMsg);
//释放资源
out.close();
}
}
//服务端
public class ServerTest {
public static void main(String[] args) throws IOException {
//创建服务端的Socket对象
ServerSocket ss = new ServerSocket(11111);
//监听客户端连接
Socket socket = ss.accept();
//获取通道内的输入流对象
InputStream in = socket.getInputStream();
//一次读取一个字节数组
byte[] bytes = new byte[1024];
int len = in.read(bytes);
String str = new String(bytes,0,len);
//展示客户端发送的数据
String ip = socket.getInetAddress().getHostAddress();
System.out.println("客户端的ip:"+ip+",发送的内容:"+str);
//服务器反馈
//获取当前绑定的端口为11111的客户端通道内的字节输出流
OutputStream out = socket.getOutputStream();
out.write("收到信息".getBytes());
//释放资源
ss.close();
}
}
7-4、案例_无限发送
需求:客户端不断键盘录入数据,(BufferedReader),客户端一旦录入"886"结束,服务器端将客户端录入的数据展示在控制台上!
//客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("10.12.151.138",33333);
//创建BufferedReader字符缓冲输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//将通过内的流封装成BufferedWriter
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while((line = br.readLine())!= null){
if("886".equals(line)){
break;
}
//字符输入流读取一行
//就给当前通过内的流写一行
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
s.close();
bw.close();
}
}
//服务端
public class ServerDemo {
public static void main(String[] args) throws IOException{
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(33333);
//监听客户端
Socket socket = ss.accept();
//封装通过通道内的字节输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//不断读数据,在控制台显示
String line = null;
while((line = br.readLine())!= null){
System.out.println(line);
}
}
}
7-5、案例_客户端键盘录入服务端输出文件
需求:客户端不断键盘录入(使用BufferReader流的方式),自定义结束条件,服务器端输出一个文本文件
//客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket socket = new Socket("10.12.151.138",22222);
//键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//封装通道内的字节输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())) ;
String line = null ;
while((line=br.readLine())!=null) {
if("over".equals(line)) {
break ;
}
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭资源
bw.close();
socket.close();
}
}
//服务端
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务端的Socket对象
ServerSocket ss = new ServerSocket(22222);
//监听客户端的连接
Socket socket = ss.accept();
//封装通道内的字节输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//创建字符缓冲输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
//一次读取一行
String line = null;
while((line = br.readLine())!= null){
bw.write(line);
bw.newLine();
bw.flush();
}
//关闭资源
bw.close();
ss.close();
}
}
7-6、案例_客户端读取文件服务端输出在控制台
需求:客户端读取文本文件,服务器将文本文件的内容输出到控制台,优先使用字符流
//客户端
public class ClientTest {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket socket = new Socket("192.168.1.110",22222);
//封装文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//封装通道内的字节输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//一次读一行数据(文件)
String line = null;
while((line = br.readLine())!= null){
bw.write(line);
bw.newLine();
bw.flush();
}
// 通知服务器,我已经传输完了
socket.shutdownOutput();
//封装通道内的字节输入流
BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//一次读取一行
String line = null;
while((line = br.readLine())!= null){
System.out.println(line);
}
//关闭资源
br.close();
br2..close();
socket.close();
}
}
//服务端
public class ServerTest {
public static void main(String[] args) throws IOException {
//创建服务器ServerSocket对象
ServerSocket ss = new ServerSocket(22222);
//监听客户端连接
Socket socket = ss.accept();
//封装通道内的字节输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//一次读取一行
String line = null;
while((line = br.readLine())!= null){
System.out.println(line);
}
//封装通道内的字节输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("我接收完毕了,你可以断开了".getBytes());
//自动根据操作系统选择对应的换行符
bw.newLine();
bw.flush();
ss.close();
}
}
7-7、案例_客户端读入文件服务端复制该文件
需求:客户端文本文件,服务器端输出一个文本文件(将客户端的文本文件中的内容复制到该文件中)
//客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建Socket对象
Socket s = new Socket("10.12.151.138",11111);
//封装文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//封装通过的内字节流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//一次读一行
String line = null;
while((line = br.readLine())!= null){
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
br.close();
s.close();
}
}
//服务端
public class ServerDemo {
public static void main(String[] args) throws IOException {
//创建服务器端Socket
ServerSocket ss = new ServerSocket(11111);
//侦听客户端
Socket s = ss.accept();
//封装通道内字节流输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
//读一行,在copy中写一行
String line = null;
while((line = br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//释放资源
bw.close();
s.close();
}
}
7-8、案例_客户端读入文件服务端输出文件并给出反馈
需求:客户端的文本文件,服务器端复制文本文件的内容到Copy.java中并且服务器加入反馈操作
readLine()方法通过返回是否null只是判断文件是否读完,服务器端通过内流的不知道文件是否已经读完了那么就会相互等待
解决:
- 在客户端告诉服务器端,没有数据了,自定义一个"字符串"作为结束标记
- public void shutdownOutput():告诉服务器,客户端没有数据了
//客户端
public class ClientDemo {
public static void main(String[] args) throws IOException {
//创建客户端的Socket对象
Socket s = new Socket("10.12.151.138",11111);
//封装文本文件
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
//封装通过的内字节输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//读内容,写进流
String line = null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义一个结束标记,作为客户端给服务器通知,文件已经读完了
/*bw.write("over");
bw.newLine();
bw.flush();*/
//告诉服务器端客户端没有数据了
s.shutdownOutput();
//接收服务器端的反馈信息
//获取通过内的字节输入流,封装成字符流
BufferedReader clientBr = new BufferedReader(new InputStreamReader(s.getInputStream()));
//利用readLine
String serverMsg = clientBr.readLine();
System.out.println("serverMsg:"+serverMsg);
//关闭
br.close();
s.close();
}
}
//服务端
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(11111);
//监听
Socket s = ss.accept();
//封装通过的内字节输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//封装被输出的文本文件Copt.txt
BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
//读取通过的流的内容,写的copy中
String line = null;
while((line = br.readLine())!= null){
/*//加入一个判断
if("over".equals(line)) {
break ;//结束
}*/
bw.write(line);
bw.newLine();
bw.flush();
}
//给客户端发送反馈信息
//服务器端获取通过的字节输出流对象(封装成字符流)
BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;
bw2.write("数据已经收到了");
bw2.newLine();
bw2.flush();
//关闭
bw.close();
s.close();
}
}
7-9、客户端读取图片服务器复制并且反馈
需求:客户端图片文件服务器将图片文件进行复制操作并且反馈
- public void flush():强制将此输出流中图片文件的缓存信息刷新出来
//客户端
public class UploadClient {
public static void main(String[] args) throws IOException{
//创建Socket
Socket s = new Socket("10.12.151.138",55555);
//封装指定的路径文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("d:\\photo.jpg"));
//封装通过内的字节输出流对象
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
//一次读取一个字节数组
byte[] bytes = new byte[1024];
int len = 0;
while((len = bis.read(bytes))!=-1){
bos.write(bytes,0,len);
//强制刷新
bos.flush();
}
//告诉服务器客户端文件读取完毕
s.shutdownInput();
//接收服务端的反馈
//获取通过内的字节输入流
InputStream in = s.getInputStream();
//一次读取一个字节数组
byte[] bytes2 = new byte[1024];
int len2 = in.read(bytes2);
String serverMsg = new String(bytes2,0,len2);
System.out.println("serMsg:" + serverMsg);
//释放资源
bis.close();
s.close();
}
}
//服务端
public class UploadServer {
public static void main(String[] args) throws IOException{
ServerSocket ss = new ServerSocket(55555);
//监听
Socket s = ss.accept();
//封装通过内的字节输入流
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
//封装图片地址
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("photocopy.jpg"));
//一次读取一个字节数组
byte[] bytes = new byte[1024];
int len = 0;
while((len = bis.read(bytes))!= -1){
bos.write(bytes,0,len);
//强制刷新流
bos.flush();
}
//发送反馈信息给 客户端
OutputStream out = s.getOutputStream();
out.write("已经收到".getBytes());
//关闭
bos.close();
s.close();
}
}
一定要注意写端口号时避免冲突,否则会抛出java.net.BindException: Address already in use: JVM_Bind 端口号冲突异常
8、TCP和UDP的区别
UDP协议:发送数据包到接收端
- 面向无连接(不需要建立连接通道)
- 不可靠连接协议,只管发送不管对方是否接收
- 发送和接收数据的执行效率高
- 发送数据大小有限制的不超过64kb
TCP协议:发送数据: 通过通过内的字节输出流OutputStream 写数据到服务器端
- 面向连接(需要建立连接通道)
- 可靠连接协议(安全的)
- 执行效率低
- 发送数据的大小无限制
9、URL