【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>.跨网络的主机间通讯 在建立通信连接的 ...
随机推荐
- 尝试阅读理解一份linux shell脚本
以下内容为本人的学习笔记,如需要转载,请声明原文链接微信公众号「englyf」https://www.cnblogs.com/englyf/p/16721350.html 从头一二去阅读语法和命令说明 ...
- ProxySQL的双层用户认证机制
转载自:https://www.likecs.com/show-203802325.html 如果使用了ProxySQL来做中间路由,那么与我们平时登录数据库有一些区别:平时我们直接使用数据库的用户密 ...
- MySQL8配置文件
- 第一个Django应用 - 第三部分:Django视图和模板
一.概述 一个视图就是一个页面,通常提供特定的功能,使用特定的模板.例如:在一个博客应用中,你可能会看到下列视图: 博客主页:显示最新发布的一些内容 每篇博客的详细页面:博客的永久链接 基于年的博客页 ...
- es分片数相关知识
分片数量 总分片数=主分片数 *(副分片数+1) 如下创建索引配置表示,总分片数=1 *(1+4),表示总共5个分片. "settings": { "number_of_ ...
- Service概述
为何需要 Service Kubernetes 中 Pod 是随时可以消亡的(节点故障.容器内应用程序错误等原因).如果使用 Deployment 运行您的应用程序,Deployment 将会在 Po ...
- <一>关于进程虚拟地址空间区域内存划分和布局
C++代码在编译完成后会生产.exe程序(windows平台), .EXE以文件的形式存储在磁盘上,当运行.exe程序的时候 操作系统会将磁盘上的.exe文件加载到内存中,那么在加载到内存中的时候,操 ...
- 华为设备配置telnet远程登陆命令
user-interface vty 0 4 进入0~4前五个的VTY用户界面进行整体配置 authentication-mode password 设置验证方式为密码 user privilege ...
- 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理
二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...
- React实现一个简易版Swiper
背景 最近在公司内部进行一个引导配置系统的开发中,需要实现一个多图轮播的功能.到这时很多同学会说了,"那你直接用swiper不就好了吗?".但其实是,因为所有引导的展示都是作为np ...