1.网络编程的目的:无线电台,信息交换
怎么做:
定位IP地址
.传输数据
2.网络通信的要素
如何实现网络通信
IP
端口号
协议:
TCP/IP参考模型
转至CSDN
TCP/IP:建立数据管道,无限制,面向连接,效率低,可靠。(打电话)
UDP:数据打包,有限制,不连接,效率高,不可靠。(发短信、视频会议)
小结:
- 网络编程中有两个主要的问题:如何准确的定位到网络上的一台和多台主机 ping网址/IP
找到主机之后如何进行通信
- 网络编程中的要素
IP和端口号 IP类
网络通信写协议 UDP和TCP类 - 万物皆对象
3.IP
IP地址: InetAddress
3.1 127.0.0.1:本机localhost
127.0.0.1 / 本机localhost
ping ipaddress #检查网络是否畅通
3.2 ip地址分类
ipv4/ipv6:
本机地址:127.0.0.1
IPV4:4个字节, 0-255 , 30亿都在北美
IPV6:16个字节 8个无符号整数
3.3公网 和 私网
ABCD类地址
192.168.xx.xx给内部组织使用
cn域名是中国,com是国际
4.查询本机地址和网站地址的方法
InetAddress的构造函数不是公开的(public),所以需要通过它提供的静态方法来获取,有以下的方法:
getByname() 方法
参数:
host - 指定的主机,或 null。
返回:
给定主机名的 IP 地址。
try {
InetAddress i=InetAddress.getByName("www.baidu.com");
System.out.println(i);
} catch (UnknownHostException e) {
e.printStackTrace();
}
//查询本机地址三种
try {
InetAddress i1=InetAddress.getByName("127.0.0.1");
InetAddress i2=InetAddress.getByName("localhost");
InetAddress i3=InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
4.端口 (PID)
端口表示计算机上的一个程序的进程
不同的进程有不同的端口号!用来区分软件
端口是由2个字节组成的,被规定能跑0-65535个
我们使用地址+端口号,就可以保证数据准确无误的发到计算机指定软件上
端口分类:
HTTP:80 www.baidu.com:80
HTTPS:443
FTP:21
Telent:23
程序注册端口:1024-49151
MySQL:3306
Oracle:1521
Tomcat:8080
netstat -ano 查看所有端口
netstat -ano 查看所有端口
netstat -ano|findstr"PID" 查看指定端口
tastlist|findstr "PID" 查看指定端口的进程
5.通信协议
**网络通信协议:**速率,传输码率,代码结构,传输控制
TCP/IP协议是一组协议
TCP:用户传输协议
UDP:用户数据报协议
TCP:打电话
- 连接,稳定
- 三次握手,四次挥手
三次握手:
A:我要开始连接了 (提问)
B: 我知道了,开始吧 (回复)
A:开始连接,连接ing (回复)
四次挥手
A:我准备走了 (提问)
B:你要走了吗 (思考)
B: 你走了吗 (回复)
A: 我走了 (回复)
3.客户端和服务端 CS
UDP:发短信
- 不连接,不稳定
- 客户端,服务端,无明确界限
- 不管能不能准备好都能发给你。
- DDOS 洪水攻击
5.TCP 通信程序
-
启动服务器
-
客户端启动,并请求客户端
-
他们要连接,而连接需要一个IO对象(字节流对象)
下面是具体的实现步骤
我们要读取本地的一个文件,然后上传到服务器,并将其保存到本地。
服务器:
注意: -
从第一步开始就要放在while循环里面,保证服务器是一直打开的。
-
接下来我们写一个线程,每次调用一个客户端就启动一个线程,剩下的2 3 4 …7步骤就放到run方法里面
while(true)
{
1. Socket socket = serverSocket.accept();
//多线程
new thread(new Runable())
{
@override
public void run ()
{
try
{
2.3...7步
}
}
}.start();
}
1 . 直接创建seversocket类对象,用它的accept方法获取客户端的socket对象
Socket socket = serverSocket.accept();
准备工作2.3
2 . 判断一下文件是否存在 File file = new File("E:\\load"); if (!file.exists()) { file.mkdirs(); }
// 优化:文件名不能一直是一个,应该随机命名 毫秒+随机数+.jpg
String filename ="文件"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
filename是文件名
3 . 创建本地字节输出流上传到硬盘,构造方法中绑定输出的目的地
fileOutputStream = new FileOutputStream(file + “\”+filename); 传输文件+随机文件名
4.5上传本地
4 .创建网络字节输入流,inputstream im =socket对象.getinputstream()读取文件
5 . 创建一个字节数组加快上传的速度 用网络字节输入流对象.read 网络读取,本地上传
byte[] bytes = new byte[1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
}
6 . 网络字节输出流中write方法 反馈信息给客户端
OutputStream outputStream = socket.getOutputStream();
outputStream.write("上传成功".getBytes());
7.关闭资源,把要关闭的流都关闭了。
fileOutputStream.close();
socket.close();
客户端
1 . 本地字节输入流对象 读取上传的文件
2. 创建客户端对象,将文件通过网络字符输出流上传,绑定端口号
Socket socket=new Socket(“localhost”,8888);
3.获取网络字节输出流对象
OutputStream outputStream=socket.getOutputStream();
4.创建字节数组加速上传, 本地输入流读取 网络输出流上传
byte [] bytes=new byte[1024];
int len=0;
while ((len=fileInputStream.read(bytes))!=-1)
{
//5.用网络字节输出流上传文件
outputStream.write(bytes,0,len);
}
//** 优化:Socket对象禁用输出流
socket.shutdownOutput();
6 .和服务器交互---------------------------------
7.获取网络字节输入流,读取服务器发回来的信息
InputStream inputStream=socket.getInputStream();
while ((len=inputStream.read(bytes))!=-1)
{
System.out.println(new String(bytes,0,len));
}
8.关闭流,要用到的流都关掉。 流对象.close()
5.1客户机和服务器交互的步骤
下面是交互的代码:
客户机:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//1.创建客户端对象,给ip和端口
Socket socket =new Socket("127.0.0.1",8888);
//2.使用Socket对象中的getOutputStream方法获取网络字节输出流对象
OutputStream os=socket.getOutputStream();
//3.使用网络字节输出流对象中的write方法,给服务器发送数据
os.write("你好服务器".getBytes());
//4.用socket获取网络字节输入流 读取字节数组
InputStream im=socket.getInputStream();
//5.利用im字节输入流对象读取服务器返回的数据
//这里自建一个数组来模拟
byte [] bytes=new byte[1024];
int len=im.read(bytes);
System.out.println(new String(bytes, 0,len));
//6.释放资源
socket.close();
}
}
服务器端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
//1.创建服务器ServerSocket对象,和系统指定的端口号
ServerSocket serverSocket=new ServerSocket(8888);
//2.使用ServerSocket.accept 方法 获取客户端对象socket
Socket socket=serverSocket.accept();
//3.用socket获取网络字节输入流
InputStream im=socket.getInputStream();
// 4.利用im字节输入流对象读取数据 读取字节数组
//这里自建一个数组来模拟
byte [] bytes=new byte[1024];
int len=im.read(bytes);
System.out.println(new String(bytes,0,len));
//5.用socket获取网络字节输出流
OutputStream os=socket.getOutputStream();
//6.利用字节输出流对象os,给客户端写数据
os.write("收到谢谢".getBytes());
//7.释放资源
socket.close();
serverSocket.close();
}
}
5.2 文件上传案例
原理:客户端读取文件,把文件上传到服务器,服务器再把上传的文件保存在服务器的硬盘上
下面是代码实现
服务器
package com.testinternet;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Random;
public class TCPServer {
public static void main(String[] args) throws IOException {
//1 创建服务器对象 对应端口号
ServerSocket serverSocket=new ServerSocket(8888);
// 2 获取客户端的socket
//** 优化:服务器不用关闭,是它一直处于激活的状态 while循环
while (true) {
Socket socket = serverSocket.accept();
// ** 优化:有一个客户端上传文件,就开始一个线程,完成文件的上传。
new Thread(new Runnable() {
@Override
public void run() {
FileOutputStream fileOutputStream = null;
try {
//3 创建网络字节输入流
InputStream inputStream = socket.getInputStream();
//4 判断一下目标文件夹是否存在
File file = new File("E:\\load");
if (!file.exists()) {
file.mkdirs();
}
/*
** 优化:文件名不能一直是一个,应该随机命名 毫秒+随机数+.jpg
*/
String filename ="文件"+System.currentTimeMillis()+new Random().nextInt(999999)+".jpg";
//5 创建本地字节输出流上传到硬盘,构造方法中绑定输出的目的地
fileOutputStream = new FileOutputStream(file + "\\"+filename);
//6.创建一个字节数组加快上传的速度 用网络字节输入流对象.read 网络读取,本地上传
byte[] bytes = new byte[1024];
int len = 0;
while ((len = inputStream.read(bytes)) != -1) {
fileOutputStream.write(bytes, 0, len);
}
//7 网络字节输出流中write方法 反馈信息给客户端
OutputStream outputStream = socket.getOutputStream();
outputStream.write("上传成功".getBytes());
//8 关闭资源
fileOutputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
}
/*
出现问题:
read方法读取不到结束标记,所以程序不会停止
所以我们在客户端可以使用socket对象.shutdown方法禁用网络输出流
*/
客户端
package com.testinternet;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
//1 本地字节输入流对象 读取上传的文件
FileInputStream fileInputStream=new FileInputStream("D:\\1.jpg");
//2 创建客户端对象,将文件通过网络字符输出流上传,绑定端口号
Socket socket=new Socket("localhost",8888);
//3 获取网络字节输出流对象
OutputStream outputStream=socket.getOutputStream();
// 4.创建字节数组加速上传, 本地输入流读取 网络输出流上传
byte [] bytes=new byte[1024];
int len=0;
while ((len=fileInputStream.read(bytes))!=-1)
{
//5.用网络字节输出流上传文件
outputStream.write(bytes,0,len);
}
//** 优化:Socket对象禁用输出流
socket.shutdownOutput();
// 和服务器交互---------------------------------
//6 获取网络字节输入流,读取服务器发回来的信息
InputStream inputStream=socket.getInputStream();
while ((len=inputStream.read(bytes))!=-1)
{
System.out.println(new String(bytes,0,len));
}
inputStream.close();
outputStream.close();
socket.close();
}
}
总结:
1.客户端和服务器的交互是通过Socket类来交互
2.服务器是不能关闭的,它要在循环里面。