网络编程
概念 服务器概念:,是一个安装了服务器软件的计算机.
网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互.
通信三要素
1.[协议]
TCP:面向连接协议:
客户端和服务端想要完成数据交互,需要三次握手
第一次握手:客户端向服务端发送连接请求
第二次握手:服务器接收请求,响应,通知客户端,我接收到了请求
第三次握手:客户端再次向服务端发送确认信息,确认连接
缺点:效率低
优点:给数据提供了一个安全的传输环境
UDP:面向无连接协议:客户端和服务端交互时,无需确认连接,就可以传输数据
优点:效率高
缺点:数据不安全,有可能在传输的过程中丢失数据包
2.[IP地址]
a.概述:指互联网协议地址(Internet Protocol Address),俗称IP计算机的唯一标识
b.作用:可用于计算机和计算机之间的连接
[端口号]: 每一个应用程序的唯一标识
实现简单客户端和服务端的交互
Socket(服务器IP,服务器分配的端口号)
步骤:
1.创建Socket对象,指定服务器的IP,以及端口号
2.使用Socket对象调用getOutputStream,获取OutputStream对象,用于往服务器发请求
3.使用Socket对象调用getInputStream,获取InputStream对象,用于读取服务器响应回来的数据
4.关闭资源
//客户端
public class Client {
public static void main(String[] args) throws IOException {
//1.创建Socket对象,指定服务器的IP,以及端口号
Socket socket = new Socket("127.0.0.1", 8888);
//2.使用Socket对象调用getOutputStream,获取OutputStream对象,用于往服务器发请求
OutputStream os = socket.getOutputStream();
os.write("我想下载电影".getBytes());
//3.使用Socket对象调用getInputStream,获取InputStream对象,用于读取服务器响应回来的数据
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//4.关闭资源
is.close();
os.close();
socket.close();
}
}
编写服务端
ServerSocket(int port) ->指定端口号
Socket accept() -> 监视是哪个客户端连接的我 , 哪个客户端连接服务端,accept方法返回的Socket就是代表哪个客户端对象,如果没有客户端连接我,accept自带阻塞功能,就一直在accept这里卡住不动,直到有客户端连接,程序才会继续往下执行
步骤:
1.创建ServerSocket指定端口号,用于客户端的连接
2.调用accept方法监视是有没有客户端连接,是哪个客户端连接
3.调用getInputStream,读取客户端发来的请求
4.调用getOutputStream,给客户端发响应结果
5.关闭资源
//服务端
public class Server {
public static void main(String[] args) throws IOException {
//1.创建ServerSocket指定端口号,用于客户端的连接
ServerSocket ss = new ServerSocket(8888);
//2.调用accept方法监视是有没有客户端连接,是哪个客户端连接
Socket socket = ss.accept();
//3.调用getInputStream,读取客户端发来的请求
InputStream is = socket.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
System.out.println(new String(bytes,0,len));
//4.调用getOutputStream,给客户端发响应结果
OutputStream os = socket.getOutputStream();
os.write("给你一个电影".getBytes());
//5.关闭资源
os.close();
is.close();
socket.close();
ss.close();
}
}
经验值传授:
Exception in thread “main” java.net.BindException: Address already in use: JVM_Bind
端口号冲突
文件上传
文件上传客户端以及服务端实现
//客户端
public class Client {
public static void main(String[] args)throws IOException {
//1.创建Socket对象,指定要连接服务端的端口号和ip
Socket socket = new Socket("127.0.0.1", 8888);
//2.创建FileInputStream用于读取本地上的图片
FileInputStream fis = new FileInputStream("F:\\Idea\\io\\24.jpg");
//3.调用Socket对象中的getOutputStream,用来将读取过来的图片写到服务器端
OutputStream os = socket.getOutputStream();
//4.边读边写
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
socket.shutdownOutput();
System.out.println("==========以下代码为读取响应===========");
//5.调用Socket对象中的getInputStream,用来读取服务端发来的响应结果
InputStream is = socket.getInputStream();
byte[] bytes1 = new byte[1024];
int len1 = is.read(bytes1);
System.out.println(new String(bytes1,0,len1));
//6.关闭资源
is.close();
os.close();
fis.close();
socket.close();
}
}
//服务端
public class Server {
public static void main(String[] args)throws IOException {
//1.创建ServerSocket对象,指定端口号
ServerSocket ss = new ServerSocket(8888);
//2.调用accept方法,等待连接的客户端对象
Socket socket = ss.accept();
//3.调用Socket中的getInputStream,读取客户端发来的图片字节
InputStream is = socket.getInputStream();
//4.创建FileOutputStream用于将读取过来的图片写到本地上
String name = System.currentTimeMillis()+""+new Random().nextInt()+".jpg";
FileOutputStream fos = new FileOutputStream("D:\\教学班级\\直播班级\\北京修正黑马JavaEE就业372期\\day16_网络编程\\资料\\img\\"+name);
//5.边读边写
byte[] bytes = new byte[1024];
int len;
while((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("==========以下代码为往客户端发送响应===========");
//6.调用Socket对象中的getOutputStream,往客户端发送响应结果
OutputStream os = socket.getOutputStream();
os.write("上传成功!".getBytes());
//7.关闭资源
os.close();
fos.close();
is.close();
socket.close();
}
}
文件上传服务端实现(多线程)
public class Server_Thread {
public static void main(String[] args) throws IOException {
//1.创建ServerSocket对象,指定端口号
ServerSocket ss = new ServerSocket(8888);
while (true) {
//2.调用accept方法,等待连接的客户端对象
Socket socket = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
try {
//3.调用Socket中的getInputStream,读取客户端发来的图片字节
InputStream is = socket.getInputStream();
//4.创建FileOutputStream用于将读取过来的图片写到本地上
String name = System.currentTimeMillis() + "" + new Random().nextInt() + ".jpg";
FileOutputStream fos = new FileOutputStream("D:\\教学班级\\直播班级\\北京修正黑马JavaEE就业372期\\day16_网络编程\\资料\\img\\" + name);
//5.边读边写
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1) {
fos.write(bytes, 0, len);
}
System.out.println("==========以下代码为往客户端发送响应");
//6.调用Socket对象中的getOutputStream,往客户端发送响应结果
OutputStream os = socket.getOutputStream();
os.write("上传成功!".getBytes());
//7.关闭资源
os.close();
fos.close();
is.close();
//socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
文件上传服务器端(连接池版本)
public class Server_Pool {
public static void main(String[] args)throws IOException {
//创建线程池对象
ExecutorService es = Executors.newFixedThreadPool(10);
//1.创建ServerSocket对象,指定端口号
ServerSocket ss = new ServerSocket(8888);
while(true){
//2.调用accept方法,等待连接的客户端对象
Socket socket = ss.accept();
es.submit(new Runnable() {
@Override
public void run() {
try{
//3.调用Socket中的getInputStream,读取客户端发来的图片字节
InputStream is = socket.getInputStream();
//4.创建FileOutputStream用于将读取过来的图片写到本地上
String name = System.currentTimeMillis()+""+new Random().nextInt()+".jpg";
FileOutputStream fos = new FileOutputStream("D:\\教学班级\\直播班级\\北京修正黑马JavaEE就业372期\\day16_网络编程\\资料\\img\\"+name);
//5.边读边写
byte[] bytes = new byte[1024];
int len;
while((len = is.read(bytes))!=-1){
fos.write(bytes,0,len);
}
System.out.println("==========以下代码为往客户端发送响应===========");
//6.调用Socket对象中的getOutputStream,往客户端发送响应结果
OutputStream os = socket.getOutputStream();
os.write("上传成功!".getBytes());
//7.关闭资源
os.close();
fos.close();
is.close();
//socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
});
}
}
}
BS架构服务器案例
/* BufferedReader(Reader in)
BufferedReader的参数位置是Reader
new BufferedReader的时候传递的只要是Reader的子类就ok
如果我们想将InputStream转成BufferedReader
我们就应该找一个跟InputStream有关的Reader的子类
那么哪个Reader的子类和InputStream有关呢?
InputStreamReader正好是Reader的子类,也正好和InputStream有关
所以可以传递InputStreamReader作为BufferedReader的参数*/
public class BS {
public static void main(String[] args)throws Exception {
//1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(8888);
while(true){
//2.调用accept方法监视客户端对象
Socket socket = ss.accept();
//3.调用getInputStream读取客户端发来的请求
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String path = br.readLine();//GET /day16/web/index.html HTTP/1.1
//3.1 调用split,根据空格切割,将path变成String数组
String[] s = path.split(" ");
String s1 = s[1];// /day16/web/index.html
//3.2 调用subString(1)从字符串的索引1开始分割,截取到最后
String ioPath = s1.substring(1);
//4.创建FileInputStream,根据解析出来的ioPath去本地上读取对应的网页
FileInputStream fis = new FileInputStream(ioPath);
//5.调用getOutputStream,将从本地上读取到的网页响应给浏览器(写)
OutputStream os = socket.getOutputStream();
//先把响应信息写到浏览器
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
os.write("\r\n".getBytes());
//6.边读编写
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//7.关闭资源
os.close();
fis.close();
br.close();
is.close();
socket.close();
}
}
}
/* BufferedReader(Reader in)
BufferedReader的参数位置是Reader
new BufferedReader的时候传递的只要是Reader的子类就ok
如果我们想将InputStream转成BufferedReader
我们就应该找一个跟InputStream有关的Reader的子类
那么哪个Reader的子类和InputStream有关呢?
InputStreamReader正好是Reader的子类,也正好和InputStream有关
所以可以传递InputStreamReader作为BufferedReader的参数 */
public class BS_Thread {
public static void main(String[] args)throws Exception {
//1.创建ServerSocket对象
ServerSocket ss = new ServerSocket(8888);
while(true){
//2.调用accept方法监视客户端对象
Socket socket = ss.accept();
new Thread(new Runnable() {
@Override
public void run() {
try{
//3.调用getInputStream读取客户端发来的请求
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String path = br.readLine();//GET /day16/web/index.html HTTP/1.1
//3.1 调用split,根据空格切割,将path变成String数组
String[] s = path.split(" ");
String s1 = s[1];// /day16/web/index.html
//3.2 调用subString(1)从字符串的索引1开始分割,截取到最后
String ioPath = s1.substring(1);
//4.创建FileInputStream,根据解析出来的ioPath去本地上读取对应的网页
FileInputStream fis = new FileInputStream(ioPath);
//5.调用getOutputStream,将从本地上读取到的网页响应给浏览器(写)
OutputStream os = socket.getOutputStream();
//先把响应信息写到浏览器
os.write("HTTP/1.1 200 OK\r\n".getBytes());
os.write("Content-Type:text/html\r\n".getBytes());
os.write("\r\n".getBytes());
//6.边读编写
byte[] bytes = new byte[1024];
int len;
while((len = fis.read(bytes))!=-1){
os.write(bytes,0,len);
}
//7.关闭资源
os.close();
fis.close();
br.close();
is.close();
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
}
}
}