2. 注意事项:
1. 常用命令:
* 查看本机IP地址:ipconfig
* 检查网络是否连通:ping 222.198.34.77
2. 特殊的IP地址
* 本机IP地址:127.0.0.1,localhost
3. IP就是电脑的唯一标识
Socket s1 = server.accept();//指定一台客户端
Socket s2 = server.accept();//指定另一台客户端
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();
//3. 使用==网络字节输出流OutputStream对象中的方法write==,给服务器发送数据
os.write("你好服务器".getBytes());
//还没有建立服务器——这里只创建了客户端
//4. 使用==Socket对象中的方法getInputStream==()获取网络字节输入流InputStream对象
//5. 使用==网络字节输入流InputStream对象中的方法read==,读取服务器回写的数据
//6. 释放资源(Socket)
socket.close();
}
//定义一个服务器端:TCPServer.java
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 server = new ServerSocket(8888);
//2. 使用ServerSocket对象中的++方法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());
//7. 释放资源(==Socket,ServerSocket==)
socket.close();
server.close();
}
}
//定义一个客户端:TCPClient.java
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. 创建一个客户端==对象Socket==,==构造方法绑定服务器的IP地址和端口号==
Socket socket = new Socket("127.0.0.1", 8888);
//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();
}
}
//客户端的结果:
收到谢谢
//服务器端的结果:
你好服务器
public class TCPClient {
public static void main(String[] args) throws IOException {
//1. 创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\picture\\1.jpg");
//2. 创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1", 8888);
//3. 使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//4. 使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
byte[] bytes = new byte[1024];
int len = 0;
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,Socket)
fis.close();
socket.close();
}
}
File file = new File("E:\\picture");
if(!file.exists()){ //是否存在
file.mkdirs(); //创建一个文件
}
FileOutputStream fos = new FileOutputStream(file + "\\1.jpg");
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. 判断E:\\picture文件夹是否存在,不存在则创建
File file = new File("E:\\picture");
if(!file.exists()){ //是否存在
file.mkdirs(); //创建一个文件
}
//5. 创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream(file + "\\1.jpg");
//6. 使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes)) != -1){
//7. 使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes, 0, len);
}
/*//8. 使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//9. 使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
os.write("上传成功".getBytes());*/
//8,9合成一个
socket.getOutputStream().write("上传成功".getBytes());
//10. 释放资源(FileOutputStream,Socket,ServerSocket)
fos.close();
socket.close();
server.close();
}
}
//改3.2客户端代码:在本地字节输入流后面
//4. 使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1){
//5. 使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes, 0, len);
}
socket.shutdownOutput();
//3.2完整代码
public static void main(String[] args) throws IOException {
//1. 创建一个本地字节输入流FileInputStream对象,构造方法中绑定要读取的数据源
FileInputStream fis = new FileInputStream("F:\\picture\\1.jpg");
//2. 创建一个客户端Socket对象,构造方法中绑定服务器的IP地址和端口号
Socket socket = new Socket("127.0.0.1", 8888);
//3. 使用Socket中的方法getOutputStream,获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//4. 使用本地字节输入流FileInputStream对象中的方法read,读取本地文件
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1){
//5. 使用网络字节输出流OutputStream对象中的方法write,把读取到的文件上传到服务器
os.write(bytes, 0, len);
}
/*5. ==解决方法【重点】==:--解决因无法上传结束标记而导致无法停止的阻塞状态
1. 上传完文件,给服务器写一个结束标记
2. void ==shutdownOutput==():禁用此套接字的输出流。(java.net包中,socket类的方法)
* 对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。
3. 写在-->客户端:本地字节输入流-->后面
*/
socket.shutdownOutput();
//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,Socket)
fis.close();
socket.close();
}
/*
自定义一个文件的命名规则:防止同名的文件被覆盖
规则:域名+毫秒值+随机数
*/
String fileName = "oop" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
//5. 创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
public static void main(String[] args) throws IOException {
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8888);
/*
让服务器一直处于监听状态(死循环accept方法)
* 有一个客户端上传文件,就保存一个文件
*/
while (true){
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
Socket socket = server.accept();
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4. 判断E:\\picture文件夹是否存在,不存在则创建
File file = new File("E:\\picture");
if(!file.exists()){ //是否存在
file.mkdirs(); //创建一个文件
}
/*
自定义一个文件的命名规则:防止同名的文件被覆盖
规则:域名+毫秒值+随机数
*/
String fileName = "oop" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
//5. 创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
//6. 使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes)) != -1){
//7. 使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes, 0, len);
}
/*//8. 使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//9. 使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
os.write("上传成功".getBytes());*/
//8,9合成一个
socket.getOutputStream().write("上传成功".getBytes());
//10. 释放资源(FileOutputStream,Socket,ServerSocket)
fos.close();
socket.close();
}
//服务器就不用关闭
//server.close();
}
public static void main(String[] args) throws IOException {
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8888);
/*
让服务器一直处于监听状态(死循环accept方法)
* 有一个客户端上传文件,就保存一个文件
*/
while (true){
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
Socket socket = server.accept();
/*
使用多线程技术,提高程序的效率
有一个客户端上传文件,就开启一个线程,完成文件的上传
*/
new Thread(new Runnable() {
//完成文件的上传
@Override
public void run() {
try {
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4. 判断E:\\picture文件夹是否存在,不存在则创建
File file = new File("E:\\picture");
if(!file.exists()){ //是否存在
file.mkdirs(); //创建一个文件
}
/*
自定义一个文件的命名规则:防止同名的文件被覆盖
规则:域名+毫秒值+随机数
*/
String fileName = "oop" + System.currentTimeMillis() + new Random().nextInt(999999) + ".jpg";
//5. 创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
FileOutputStream fos = new FileOutputStream(file + "\\" + fileName);
//6. 使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes)) != -1){
//7. 使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
fos.write(bytes, 0, len);
}
/*//8. 使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
//9. 使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
os.write("上传成功".getBytes());*/
//8,9合成一个
socket.getOutputStream().write("上传成功".getBytes());
//10. 释放资源(FileOutputStream,Socket,ServerSocket)
fos.close();
socket.close();
}catch (IOException e){
System.out.println(e);
}
}
}).start();
}
//服务器就不用关闭
//server.close();
}
//定义了一个服务器(默认状态)
public static void main(String[] args) throws IOException {
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8080);
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象(浏览器)
Socket socket = server.accept();
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4. 使用网络字节输入流InputStream对象中的方法read,读取客户端的请求信息
byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes)) != -1){
System.out.println(new String(bytes, 0, len));
}
}
//网页访问http://127.0.0.1:8080/day11/web/index.html是回显
GET /day11/web/index.html HTTP/1.1
Host: 127.0.0.1:8080
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36 Core/1.70.3754.400 QQBrowser/10.5.3991.400
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
原来的:
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8080);
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象(浏览器)
Socket socket = server.accept();
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//获取回写内容的第一行中的路径步骤:
//1. 把is网络字节输入流对象(InputStream),转换为字符缓冲输入流(BufferedReader)
//InputStreamReader是字节流通向字符流的桥梁
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//2. 把客户端请求信息的第一行读取出来 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html HTTP/1.1
//用到BufferedReader特有的方法,readLine-->读取一行,返回类型字符串
String line = br.readLine();
//3. 把读取的信息进行切割,只要中间部分 /Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html
//用String中的split方法,用空格来切割-->返回的是字符串数组
String[] arr = line.split(" ");
//4. 把路径前面的/去掉,进行截取 Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html
//用String中的substring方法,从1开始截取保留后面的
String htmlpath = arr[1].substring(1); //这里出来的就是html的路径了
// 根据路径读取本地文件,步骤:
//1. 创建一个本地字节输入流,构造方法中绑定要读取的html路径
FileInputStream fis = new FileInputStream(htmlpath);
//2. 使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
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());
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1){
os.write(bytes, 0, len);
}
fis.close();
socket.close();
server.close();
//定义了一个服务器:TCPServer.java
public static void main(String[] args) throws IOException {
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8080);
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象(浏览器)
Socket socket = server.accept();
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//4. 使用网络字节输入流InputStream对象中的方法read,读取客户端的请求信息
/*byte[] bytes = new byte[1024];
int len = 0;
while((len = is.read(bytes)) != -1){
System.out.println(new String(bytes, 0, len));
}*/
//获取回写内容的第一行中的路径步骤:
//1. 把is网络字节输入流对象(InputStream),转换为字符缓冲输入流(BufferedReader)
//InputStreamReader是字节流通向字符流的桥梁
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//2. 把客户端请求信息的第一行读取出来 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html HTTP/1.1
//用到BufferedReader特有的方法,readLine-->读取一行,返回类型字符串
String line = br.readLine();
//3. 把读取的信息进行切割,只要中间部分 /Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html
//用String中的split方法,用空格来切割-->返回的是字符串数组
String[] arr = line.split(" ");
//4. 把路径前面的/去掉,进行截取 Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html
//用String中的substring方法,从1开始截取保留后面的
String htmlpath = arr[1].substring(1); //这里出来的就是html的路径了
// 根据路径读取本地文件,步骤:
//1. 创建一个本地字节输入流,构造方法中绑定要读取的html路径
FileInputStream fis = new FileInputStream(htmlpath);
//2. 使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
// 写入HTTP协议响应头,固定写法
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文件回写到客户端(页面上)
byte[] bytes = new byte[1024];
int len = 0;
while((len = fis.read(bytes)) != -1){
os.write(bytes, 0, len);
}
//释放资源
fis.close();
socket.close();
server.close();
}
1. 使用多线程技术,提高程序的效率
* 有一个客户端上传文件,就开启一个线程,完成文件的上传while
2. 注:实现Runnable接口,重写run方法时候【重点】
* 接口中的run方法没有声明抛出异常
* 所以子类重写方法是也不能声明抛出异常
* 需要用到try...catch
* catch中写:IOException
//定义一个服务器:TCPServerThread.java
public static void main(String[] args) throws IOException {
//1. 创建一个服务器ServerSocket对象,和系统要指定的端口号
ServerSocket server = new ServerSocket(8080);
/*
浏览器解析服务器回写的html页面,页面中如果有图片,那么浏览器就会单独的开启一个线程,读取服务器的图片
我们就的让服务器一直处于监听状态
*/
while (true){
//2. 使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象(浏览器)
Socket socket = server.accept();
/*
使用多线程技术,提高程序的效率
客户端请求一次,服务器就回写一次
*/
new Thread(new Runnable() {
@Override
public void run() {
try {
//3. 使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
InputStream is = socket.getInputStream();
//获取回写内容的第一行中的路径步骤:
//1. 把is网络字节输入流对象(InputStream),转换为字符缓冲输入流(BufferedReader)
//InputStreamReader是字节流通向字符流的桥梁
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//2. 把客户端请求信息的第一行读取出来
//用到BufferedReader特有的方法,readLine-->读取一行,返回类型字符串
String line = br.readLine();
//System.out.println(line); //有一张图片就请求一次(演示)
//3. 把读取的信息进行切割,只要中间部分
//用String中的split方法,用空格来切割-->返回的是字符串数组
String[] arr = line.split(" ");
//4. 把路径前面的/去掉,进行截取
//用String中的substring方法,从1开始截取保留后面的
String htmlpath = arr[1].substring(1); //这里出来的就是html的路径了
// 根据路径读取本地文件,步骤:
//1. 创建一个本地字节输入流,构造方法中绑定要读取的html路径
FileInputStream fis = new FileInputStream(htmlpath);
//2. 使用Socket中的方法getOutputStream获取网络字节输出流OutputStream对象
OutputStream os = socket.getOutputStream();
// 写入HTTP协议响应头,固定写法
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文件回写到客户端(页面上)
byte[] bytes = new byte[1024];
int len = 0;
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();
}
2. 客户端请求信息演示(有一个图片请求一次)
* 在readLine读取一行的方法后面输出line
结果: GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/index.html HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/logo2.png HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/header.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/1.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/title2.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/small03.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/middle01.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/big01.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/ad.jpg HTTP/1.1 GET /Dark-horse-teaching/src/cn/javaadvance/day11/web/img/footer.jpg HTTP/1.1
* 除了第一次是请求客户端信息外,后面每有一个图片就请求一次