【Java SE进阶】Day11 网络编程、TCP应用程序
一、网络编程入门
1、软件架构
- C/S:QQ、迅雷
- B/S
- 共同点:都离不开网络的支持
- 网络编程:在一定的协议下,实现两台计算机通信
2、网络通信协议
- 通信协议:需遵守的规则,只有遵守才能通信
- 主要包括:传输格式、传输速率、传输步骤
- TCP/IP协议:
- 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol)
- 是Internet最基本、最广泛的协议
- 内部包含了一系列处理数据通信的协议,并采用四层分层模型(下层为上层提供服务)
- 核心层:网络层,将数据分组,并将分组后的传输到计算机网络中
3、协议分类
- UDP:用户数据报协议(User Datagram Protocol)
- 无需连接,数据直接发送,传输快,不可靠,数据被限制在64kb内
- 例子:QQ聊天、在线视频会议
- TCP:传输控制协议 (Transmission Control Protocol)
- 使用三次握手建立双端连接,可靠无差错的数据传输,数据安全
- 例子:文件传输,网页浏览、看视频
4、网络编程三要素
- 组成:协议、IP地址、端口号(标识唯一设备)
- IPV4:32位二进制,地址资源有限
- IPV6:128位,8组16进制
- 常用命令:ipconfig,特殊ip
- 端口号(标识设备的多个进程)
- 利用协议 + IP地址 + 端口号三元组,与其他进程交互
- 0-65536,普通程序使用1024以上的
- 常用端口号:
- http/Nginx:80
- https:443
- Tomcat:8080
- Oracle:1521
- Redis:6379
IP地址:
二、TCP应用程序
1、概述
- TCP通信实现两端(客户端(Client)与服务端(Server))的数据交互
- 两个套接字类:Socket发请求/ServerSocket(构造传递端口)响应请求
- 步骤:
- 先启动服务器端,经过三次握手
- 客户端请求服务器端
- 建立连接,通过IO对象(字节流对象)通信
- 服务器使用客户端的流与客户端发送数据和回写数据
- 说明:
- 与多个服务器端交互,可以使用accept获取指定对象:Socket s1=server.accept()
2、代码实现
- 服务器端代码
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.创建服务器ServerSocket对象和系统要指定的端口号
ServerSocket server=new ServerSocket(8888);
//2.使用SeverSocket对象中的方法accept,获取到请求的客户端对象Socket
Socket socket=server.accept();
//3.使用Socket对象中的方法getInputStream读取网络字节输入流InputStream对象
InputStream is=socket.getInputStream();
//4.使用网络字节输入流InputStream对象中的方法read,读取客户端发送的数据
byte[] bytes=new byte[1024];
//读取一次就够了
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
//5.使用Socket对象中的方法getOutputStream()读取网络字节输出流OutputStream对象
OutputStream os=socket.getOutputStream();
//6.使用网络字节输出流OutputStream对象中的方法write,往客户端回写数据
os.write("收到,谢谢".getBytes());
//6.释放资源(socket)
socket.close();
server.close();
}
}
- 客户端代码
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建客户端对象,构造方法绑定服务器端
Socket socket=new Socket("127.0.0.1",8888);
//只有客户端,抛出异常java.net.ConnectException
//2.使用Socket对象中的方法getOutputStream()读取网络字节输出流OutputStream对象
OutputStream os=socket.getOutputStream();
//3.使用网络字节输出流OutputStream对象中的方法write,往服务器发送数据
os.write("你好,服务器".getBytes());
//4.使用Socket对象中的方法getInputStream读取网络字节输入流InputStream对象
InputStream is=socket.getInputStream();
//5.使用网络字节输入流InputStream对象中的方法read,读取服务器回写的数据
byte[] bytes=new byte[1024];
//读取一次就够了
int len=is.read(bytes);
System.out.println(new String(bytes,0,len));
//6.释放资源(socket)
socket.close();
}
}
三、综合案例:文件上传下载
1、原理
- 注意:
- 与硬盘读写,自己创建字节流对象
- C/S读写,使用socket创建字节流对象
- IO流对象使用Socket套接字
2、客户端
public class TCPClient {
public static void main(String[] args) throws IOException {
//1、创建一个本地字节输入流FileInputStream对象,构造方法中绑定读取的数据源【从指定路径中读出文件】
FileInputStream fis=new FileInputStream("c:\\1.jpg");
//2、创建一个客户端Socket对象,构造方法中绑定服务器的ip地址和端口号【io对象用于传送数据和接收数据】
Socket socket=new Socket("127.0.0.1",8888);
//3、使用Socket中的方法getOutputStream获取网络字节输出流对象OutputStream对象【获得网络输出流对象,上传】
OutputStream os=socket.getOutputStream();
//4、使用本地的字节输入流对象FileInputStream对象中的方法read,读取本地的文件【读取指定路径文件的内容】
int len=0;
byte[] bytes=new byte[1024];
//循环读取文件
while((len=fis.read(bytes))!=-1){
//5、使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes,0,len);
}
//6、使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象【获得服务器端发送的数据】
InputStream is=socket.getInputStream();
//7、使用网络字节输入流InputStream对象中的read方法读取服务器回写的数据【读取并输出从服务器返回的数据】
while((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//8、释放资源(FileInputstream,Scoket)
fis.close();
socket.close();
}
}
3、服务器端(先运行)
public class TCPServer {
public static void main(String[] args) throws IOException {
//1、创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server=new ServerSocket(8888);
//2、使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
Socket socket=server.accept();
//3、使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is=socket.getInputStream();
//4、判断d:\\upload文件夹是否存在,不存在则创建
File file=new File("d:\\upload");
if (!file.exists()){
file.mkdirs();
}
//5、创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos=new FileOutputStream(file+"\\1.jpg");//不加\\文件会上传至D盘根目录,作为upload1.jpg文件
//6、使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
int len=0;
byte[] bytes=new byte[1024];
while((len=is.read(bytes))!=-1){
//7、使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes,0,len);
}
//8、使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
//只调用一次,不创建对象
//9、使用网络字节输出流OutputStream对象中的方法write,给客户端回写“上传成功”
socket.getOutputStream().write("上传成功".getBytes());
//10、释放资源(FileOutputStream,Socket,ServerSocket)
socket.close();
server.close(); }
}
4、文件上传案例阻塞问题
从此输入流中读取一个数据字节。如果没有输入可用,则此方法将阻塞。
结束标志:读取到-1结束,不会读取到-1,也不会把结束标志写入服务器
服务器读取不到,就会进入阻塞状态,一直死循环等待结束标记
- 解决:上传完文件,给服务器一个结束标记
public class TCPClient {
public static void main(String[] args) throws IOException {
//1、创建一个本地字节输入流FileInputStream对象,构造方法中绑定读取的数据源【从指定路径中读出文件】
FileInputStream fis=new FileInputStream("c:\\1.jpg");
//2、创建一个客户端Socket对象,构造方法中绑定服务器的ip地址和端口号【io对象用于传送数据和接收数据】
Socket socket=new Socket("127.0.0.1",8888);
//3、使用Socket中的方法getOutputStream获取网络字节输出流对象OutputStream对象【获得网络输出流对象,上传】
OutputStream os=socket.getOutputStream();
//4、使用本地的字节输入流对象FileInputStream对象中的方法read,读取本地的文件【读取指定路径文件的内容】
int len=0;
byte[] bytes=new byte[1024];
//循环读取文件
while((len=fis.read(bytes))!=-1){
//5、使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes,0,len);
}
//6、使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象【获得服务器端发送的数据】
/*
写结束标记
net中的方法 java.net.Socket
void shutdownOutput() 禁用此套接字的输出流。
禁用此套接字的输出流。对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。
* */
socket.shutdownOutput();//告诉服务器,输出流已经结束
InputStream is=socket.getInputStream();
System.out.println("33333333333333333333333"); //7、使用网络字节输入流InputStream对象中的read方法读取服务器回写的数据【读取并输出从服务器返回的数据】
while((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
System.out.println("44444444444444444444444");
//8、释放资源(FileInputstream,Scoket)
fis.close();
socket.close();
}
}
5、文件上传案例优化
- 文件命名:新建命名规则
- 循环接收:accept方法放到死循环中,同时不关闭服务器端ServerSocket对象
- 多线程提高效率:上传文件的操作放入run中,每上传一个文件,开启一个线程
- 服务器端程序
public class TCPServer {
public static void main(String[] args) throws IOException {
//1、创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server=new ServerSocket(8888);
//2、使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
/*
让服务器一直处于监听状态(死循环accept方法)
有一个客户端上传文件,就保存一个文件
* */
while (true) {
Socket socket=server.accept();
/*
使用多线程提高程序的效率
只要有一个客户端上传文件,就开启一个线程,完成文件的上传
* */
new Thread(new Runnable() {
@Override
public void run() {
//开启一个线程,完成文件的上传
try {
//3、使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4、判断d:\\upload文件夹是否存在,不存在则创建
File file = new File("d:\\upload");
if (!file.exists()) {
file.mkdirs();
}
//5、创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
/*
自定义一个文件的命名规则,防止同名的文件覆盖
规则:域名+毫秒值+随机数
* */
String fileName = "itcast" + System.currentTimeMillis() + new Random().nextInt() + ".jpg";
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
//6、使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
int len = 0;
byte[] bytes = new byte[1024];
while ((len = is.read(bytes)) != -1) {
//7、使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes, 0, len);
}
//8、使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
//9、使用网络字节输出流OutputStream对象中的方法write,给客户端回写“上传成功”
socket.getOutputStream().write("上传成功".getBytes());
//10、释放资源(FileOutputStream,Socket,ServerSocket)
socket.close();
}
catch (IOException e){
e.printStackTrace();
System.out.println(e);
}
}
}).start();
}
//服务器不再关闭
//server.close();
}
}
- 客户端程序
public class TCPClient {
public static void main(String[] args) throws IOException {
//1、创建一个本地字节输入流FileInputStream对象,构造方法中绑定读取的数据源【从指定路径中读出文件】
FileInputStream fis=new FileInputStream("c:\\1.jpg");
//2、创建一个客户端Socket对象,构造方法中绑定服务器的ip地址和端口号【io对象用于传送数据和接收数据】
Socket socket=new Socket("127.0.0.1",8888);
//3、使用Socket中的方法getOutputStream获取网络字节输出流对象OutputStream对象【获得网络输出流对象,上传】
OutputStream os=socket.getOutputStream();
//4、使用本地的字节输入流对象FileInputStream对象中的方法read,读取本地的文件【读取指定路径文件的内容】
int len=0;
byte[] bytes=new byte[1024];
//循环读取文件
while((len=fis.read(bytes))!=-1){
//5、使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes,0,len);
}
//6、使用Socket中的方法getInputStream,获取网络字节输入流InputStream对象【获得服务器端发送的数据】
/*
写结束标记
net中的方法 java.net.Socket
void shutdownOutput() 禁用此套接字的输出流。
禁用此套接字的输出流。对于TCP套接字,任何以前写入的数据都将被发送,并且后跟TCP的正常连接终止序列。
* */
socket.shutdownOutput();//告诉服务器,输出流已经结束
InputStream is=socket.getInputStream();
//7、使用网络字节输入流InputStream对象中的read方法读取服务器回写的数据【读取并输出从服务器返回的数据】
while((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//8、释放资源(FileInputstream,Scoket)
fis.close();
socket.close();
}
}
四、模拟B/S服务器
1、分析
只要访问该端口的指定地址,就访问页面头的路径,将html内容写回到客户端
- 使用浏览器作为客户端
- 目的:服务器给客户端回写一个信息,回写一个html文件,即需要读取该文件
2、服务器端
package com.liujinhui.Day1206Net.BSTCP;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
创建BS版本TCP服务器
* */
public class TCPServer {
public static void main(String[] args) throws IOException {
//创建一个服务器ServerScoket,和系统要指定的端口号
ServerSocket server =new ServerSocket(8080);
//使用accept方法,获取到请求的客户端对象(浏览器)
Socket socket=server.accept();
//使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is=socket.getInputStream();
//使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
/* byte[] bytes=new byte[1024];
int len=0;
while((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}*/
//把is网络字节输入流对象,转换为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//读取客户端请求信息的第一行GET /MyJavaProject/web/index.html HTTP/1.1
String line=br.readLine();
System.out.println(line);
//把读取的信息进行切割,只要中间的部分
String[] arr = line.split(" ");
//把路径前面的/去掉,进行截取
String htmlPath = arr[1].substring(1);
System.out.println(htmlPath);
//根据此路径读取此文件
//创建一个本地字节输入流,绑定读取的html路径
//项目根目录不一样!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
FileInputStream fis=new FileInputStream("web/index.html");
//使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
OutputStream os=socket.getOutputStream();
//写入HTTP协议响应头,固定写法【html中会讲】
os.write("HTTP/1.1 200 0K\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
//必须要写入空行,否则浏览器不解析
os.write("\r\n".getBytes());
//一读一写复制文件,把服务器读取的html文件写到客户端
int len=0;
byte[] bytes=new byte[1024];
while((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//释放资源
fis.close();
socket.close();
server.close(); //浏览器访问http://127.0.0.1:8080/MyJavaProject/web/index.html
//打印一堆信息,客户端是IE的浏览器
}
}
- 优化:多线程一直保持监听,保证浏览器可以正常读取图片
package com.liujinhui.Day1206Net.BSTCP;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*
创建BS版本TCP服务器
* */
public class TCPServerThread {
public static void main(String[] args) throws IOException {
//创建一个服务器ServerScoket,和系统要指定的端口号
ServerSocket server =new ServerSocket(8080);
/*
浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
我们需要让服务器一直处于监听状态,客户端请求一次,服务器就回写一次
* */
while(true){
//一直处于监听状态
Socket socket=server.accept();
new Thread(new Runnable() {
@Override
public void run() {
try{
//使用accept方法,获取到请求的客户端对象(浏览器)
//使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is=socket.getInputStream();
//使用网络字节输入流InputStream对象中的方法read读取客户端的请求信息
/* byte[] bytes=new byte[1024];
int len=0;
while((len=is.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}*/
//把is网络字节输入流对象,转换为字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//读取客户端请求信息的第一行GET /MyJavaProject/web/index.html HTTP/1.1
String line=br.readLine();
//打印请求的路径
System.out.println(line);
//把读取的信息进行切割,只要中间的部分
String[] arr = line.split(" ");
//把路径前面的/去掉,进行截取
String htmlPath = arr[1].substring(1);
//根据此路径读取此文件
//创建一个本地字节输入流,绑定读取的html路径
FileInputStream fis=new FileInputStream(htmlPath);
//使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
OutputStream os=socket.getOutputStream();
//写入HTTP协议响应头,固定写法【html中会讲】
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
//必须要写入空行,否则浏览器不解析
os.write("\r\n".getBytes());
//一读一写复制文件,把服务器读取的html文件写到客户端
int len=0;
byte[] bytes=new byte[1024];
while((len=fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//释放资源
fis.close();
socket.close();
}
catch(IOException e){
System.out.println(e);
}
}
}).start();
} //server.close();
//浏览器访问http://127.0.0.1:8080/web/index.html
//打印一堆信息,客户端是IE的浏览器
}
}
【Java SE进阶】Day11 网络编程、TCP应用程序的更多相关文章
- JAVA基础知识之网络编程——-TCP/IP协议,socket通信,服务器客户端通信demo
OSI模型分层 OSI模型是指国际标准化组织(ISO)提出的开放系统互连参考模型(Open System Interconnection Reference Model,OSI/RM),它将网络分为七 ...
- 网络编程TCP协议-聊天室
网络编程TCP协议-聊天室(客户端与服务端的交互); <span style="font-size:18px;">1.客户端发数据到服务端.</span> ...
- 20165310 Java实验五《网络编程与安全》
20165310 Java实验五<网络编程与安全> 任务一 题目:①编写MyBC.java实现中缀表达式转后缀表达式的功能:②编写MyDC.java实现从上面功能中获取的表达式中实现后缀表 ...
- Socket网络编程(TCP/IP/端口/类)和实例
Socket网络编程(TCP/IP/端口/类)和实例 原文:C# Socket网络编程精华篇 转自:微冷的雨 我们在讲解Socket编程前,先看几个和Socket编程紧密相关的概念: TCP/IP层次 ...
- GO语言练习:网络编程 TCP 示例
1.代码 2.编译及运行 1.网络编程 TCP 示例 simplehttp.go 代码 package main import ( "net" "os" &qu ...
- JAVA基础知识之网络编程——-网络基础(Java的http get和post请求,多线程下载)
本文主要介绍java.net下为网络编程提供的一些基础包,InetAddress代表一个IP协议对象,可以用来获取IP地址,Host name之类的信息.URL和URLConnect可以用来访问web ...
- C#网络编程TCP通信实例程序简单设计
C#网络编程TCP通信实例程序简单设计 采用自带 TcpClient和TcpListener设计一个Tcp通信的例子 只实现了TCP通信 通信程序截图: 压力测试服务端截图: 俩个客户端链接服务端测试 ...
- Java基础教程:网络编程
Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...
- 网络编程——TCP协议、UDP协议、socket套接字、粘包问题以及解决方法
网络编程--TCP协议.UDP协议.socket套接字.粘包问题以及解决方法 TCP协议(流式协议) 当应用程序想通过TCP协议实现远程通信时,彼此之间必须先建立双向通信通道,基于该双向通道实现数 ...
- Socket网络编程-TCP编程
Socket网络编程-TCP编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.socket介绍 1>.TCP/IP协议 2>.跨网络的主机间通讯 在建立通信连接的 ...
随机推荐
- ProxySQL Cluster 高可用集群 + MySQL MGR环境部署 (多写模式) 部署记录
文章转载自:https://blog.51cto.com/u_6215974/4937192 ProxySQL 在早期版本若需要做高可用,需要搭建两个实例,进行冗余.但两个ProxySQL实例之间的数 ...
- 关于使用kuboard安装其自带的监控应用的注意事项
在安装过程中若想监控kube-controller-manager和kube-scheduler,需要按步骤中的如下说明操作 在这里,所有master节点的这俩文件都需要修改,不用apply,等一分钟 ...
- Elasticsearch:跨集群复制 Cross-cluster replication(CCR)
- 苹果手机安装郑好办手机app后给绿城通公交卡充值的步骤
1.苹果手机,需要带有NFC功能 苹果XS手机该功能默认是开启的,不用额外的其他操作 苹果11该功能需要设置开启才行.步骤:设置--通用--NFC,然后开启 2,公交卡 如下这种的公交卡可以充值: 如 ...
- STM32F0单片机基于Hal库温控智能风扇
一.项目概述 设计采用STM32F0系列单片机做主控芯片,通过DHT11采集温湿度,将温度显示在OLED 屏幕上.根据温度的不同,利用STM32对风扇进行调速,总体硬件设计如下图所示 1.效果展示 2 ...
- 微信小程序开发优化
一.开发优化一 1.使用Vant Weapp 1.1 什么是Vant Weapp Vant Weapp官网链接 Vant Weapp是有赞前端团队开源的一套小程序UI组件库,助力开发者快速搭建小程序应 ...
- springboot H2 linux下搭建使用
这次研究是H2数据库了,关键还是再Linux下进行搭建部署的,被这个数据库快弄死了弄了4天时间,现在大致可以用了,还有些细节需要修正. 我这边使用的是springboot集成模式.直接使用代码启停方式 ...
- 『现学现忘』Git后悔药 — 32、revert撤销(一)
目录 1.Git的三种后悔药 2.revert命令原理 3.revert命令的使用 (1)移除某次提交的修改 (2)revert命令说明 1.Git的三种后悔药 在Git中后悔药有三种:amend.r ...
- python2与python区别汇总
目录 输入与输出 range使用区别 字符编码区别 输入与输出 python2与python3中两个关键字的区别 python2中 input方法需要用户自己提前指定数据类型 写什么类型就是什么类型 ...
- commons-fileupload组件和commons-io组件的详细下载
commons-fileupload组件和commons-io组件的详细下载 1. commons-fileupload组件的下载 下载地址:http://commons.apache.org/fil ...