1.网络编程
2.TCP网络编程
一.网络编程
软件架构
C/S架构: 客户端/服务器 比如:QQ,百度网盘,淘宝App
B/S结构: 浏览器/服务器 比如:网页QQ,网页淘宝
网络通讯协议:网络:互联网。局域网 ---通信:数据传输,-- 协议,规则规范
TCP,IP协议
TCP协议:传输控制协议,
IP协议:因特网协议
3.java中支持的常见协议
TCP协议: 传输控制协议
特点: 面向有连接(数据传输之前必须先建立连接,底层是通过"三次握手"建立连接)
优点: 保存数据是完整,安全的
缺点: 性能较低
UDP协议: 用户数据报协议
特点: 面向无连接(数据传输时不需要关系对方是否存在,甚至不需要关系对象是否开机)
缺点: 不能保证数据完整和不能保证安全的
优点: 性能较高
4.网络编程的三要素
1.网络通信协议
2.IP地址: 每台连接到互联网的计算机的唯一标识(就类似于人的身份证号,或者电话机的电话号码)
组成:由32位二进制组成 0110 0100 0100 0100 0100 0110 0100 0110
我们通常会搞成10进制: 192.168.120.250
3.端口号: 一台计算机上不同软件的标识
端口号一共有0-65535号,其中1024以下的端口被软件厂商占用!!(我们写软件时,用1024以上的)
ip地址分类
IPv4版本:由32位二进制组成,大概42亿种IP,面临枯竭
IPv6版本:由128位二进制组成,大概有可以给地球上每一粒沙子搞一个IP且不重复
IP地址的相关命令
ipconfig:查看本机IP
ping 对方IP: 测试你和对象网络是否畅通/通畅
特殊的IP地址
127.0.0.1(localhost): 本机回环地址(相当于Java中this)
InetAddress类
a.InetAddress类代表IP地址类
b.获取本地IP
InetAddress.getLocalHost();//获取主机(本机)的IP地址对象
c.获取其他机器的IP
InetAddress.getByName(域名/IP地址);//获取其他机器的IP地址对象
d.成员方法
String getHostName();获得主机名
String getHostAddress();获得IP地址字符串
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//1.获取本机的ip地址对象
InetAddress local = InetAddress.getLocalHost();
System.out.println(local);//DESKTOP-7CI8PTA/192.168.1.8
//2.获取其他机器的IP地址对象
InetAddress address = InetAddress.getByName("www.baidu.com");
System.out.println(address);//www.baidu.com/36.102.44.96
//3.成员方法
String hostName = address.getHostName();
String hostAddress = address.getHostAddress();
System.out.println(hostName);
System.out.println(hostAddress);
}
}
二。TCP通信
TCP通信分为客户端和服务器端
TCP中的两个重要的类
Socket类,代表客户端类 套接字
ServerSocket类,代表服务器端类 服务器端套接字
Socket类构造方法:
public Socket(String ip,int port);//服务器的IP地址,服务器的端口号
此构造非常牛逼!! 会根据传入的参数,自动去连接服务器
如果连接成功,那么对象正常创建
如果连接失败,那么直接抛出异常!!
常用方法:‘
public OutputStream getOutputStream();//获取连接通道中输出流
public InputStream getInputStream();//获取连接通道中输入流
public void shutDownOutput();//关闭连接通道中的输出流
public void shutDownInput();//关闭连接通道中的输入流
public void close();//关闭客户端对象
ServerSocket类
构造方法:
public ServerSocket(int port);//指定服务器端使用的端口号
常用成员方法:
public Socket accept();//接收连接到服务器的那个Socket对象,如果暂时没有客户端,该方法会阻塞
public void close(); //关闭服务器端对象
注意: 服务器获取到客户端对象之后,也可以获取连接中两个流,
但是获取时是输入流还是输出流,相当于服务器而言了
简单的TCP通信实现
客户端给服务器发送信息,服务器不回!
public class SocketDemo {
public static void main(String[] args) throws IOException {
//1.创建Socket对象
Socket socket = new Socket("127.0.0.1",8888);
System.out.println("连接服务器成功...");
//2.获取输出流
OutputStream out = socket.getOutputStream();
//3.调用输出流的write方法
out.write("你好我是客户端!".getBytes());
System.out.println("数据发送成功...");
//4.释放资源
out.close();
socket.close();
System.out.println("客户端关闭了...");
}
}
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//1.创建ServerSocket对象
ServerSocket server = new ServerSocket(8888);
System.out.println("服务器启动了...");
//2.接收连接到的客户端对象
Socket socket = server.accept(); //阻塞
System.out.println("有客户端来了...");
//3.获取输入流
InputStream in = socket.getInputStream();
//4.调用输入流的read方法
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("客户端说:"+new String(bs,0,len));
//5.释放资源
in.close();
socket.close();
server.close();
}
}
实现简单的TCP通信实现双向
客户端给服务器发信息,服务器接收到之后,给客户端回信息
public class SocketDemo {
public static void main(String[] args) throws IOException {
//客户端步骤:
//1.创建Socket对象
Socket socket = new Socket("127.0.0.1",9999);
System.out.println("连接成功...");
//2.获取输出流
OutputStream out = socket.getOutputStream();
//3.调用输出流的write方法
out.write("你好,我又来了...".getBytes());
System.out.println("发送成功...");
//==读取服务器回的信息==
//4.获取输入流
InputStream in = socket.getInputStream();
//5.调用输入流的read方法
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("服务器回复:" + new String(bs, 0, len));
//================
//6.释放资源
in.close();
out.close();
socket.close();
System.out.println("客户端关闭...");
}
}
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//服务器的步骤
//1.创建ServerSocket对象
ServerSocket server = new ServerSocket(9999);
System.out.println("服务器启动...");
//2.接收连接到的客户端对象
Socket socket = server.accept();//阻塞
System.out.println("客户端来了...");
//3.获取输入流
InputStream in = socket.getInputStream();
//4.调用输入流的read方法
byte[] bs = new byte[1024];
int len = in.read(bs);
System.out.println("客户端说:" + new String(bs, 0, len));
//=======回信息========
//5.获取输出流
OutputStream out = socket.getOutputStream();
//6.调用输出流的write方法
out.write("您的信息我收到了,安息吧!".getBytes());
System.out.println("成功回复...");
//====================
//7.释放资源
out.close();
in.close();
socket.close();
server.close();
System.out.println("服务器关闭...");
}
}
三。综合案例
文件上传:上传图片
//客户端代码实现
public class SocketDemo {
public static void main(String[] args) throws IOException {
//文件上传客户端步骤:
//1.创建Socket
Socket socket = new Socket("127.0.0.1",9999);
System.out.println("连接成功...");
//2.获取输出流
OutputStream out = socket.getOutputStream();
//3.创建文件的输入流
FileInputStream fis = new FileInputStream("555.png");
//循环:一边读文件,一边发送
byte[] bs = new byte[1024];
int len = 0;
while ((len = fis.read(bs)) != -1) {
out.write(bs,0,len);
}
//添加一句代码,告知服务器文件发送完毕
socket.shutdownOutput();
System.out.println("文件上传完毕...");
//4.获取输入流
InputStream in = socket.getInputStream();
//5.读取服务器回复的信息
len = in.read(bs);
System.out.println("服务器回复:" + new String(bs, 0, len));
//6.释放资源
in.close();
fis.close();
out.close();
socket.close();
System.out.println("客户端关闭...");
}
}
//服务器代码实现
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//文件上传服务器步骤:
//1.创建ServerSocket
ServerSocket server = new ServerSocket(9999);
System.out.println("服务器启动...");
//2.获取客户端
Socket socket = server.accept();
System.out.println("有客户端来了...");
//3.获取输入流
InputStream in = socket.getInputStream();
//4.创建文件的输出流
FileOutputStream fos = new FileOutputStream(System.currentTimeMillis()+".png");
//循环:一边读数据,一边写文件
byte[] bs = new byte[1024];
int len = 0;
while ((len = in.read(bs)) != -1) {
fos.write(bs, 0, len);
}
System.out.println("文件保存成功...");
//5.获取输出流
OutputStream out = socket.getOutputStream();
//6.给客户端回信息
out.write("您的图片我收到了,安息吧~~".getBytes());
System.out.println("消息回复成功...");
//7.释放资源
out.close();
fos.close();
in.close();
socket.close();
server.close();
System.out.println("服务器关闭...");
}
}
扩展:服务器多线程版本
public class ServerSocketMultiDemo {
public static void main(String[] args) throws IOException {
//文件上传服务器步骤:
//1.创建ServerSocket
ServerSocket server = new ServerSocket(9999);
System.out.println("服务器启动...");
//2.获取客户端
while (true) {
Socket socket = server.accept();
System.out.println("有客户端来了...");
//创建线程
new Thread(()->{
try {
//3.获取输入流
InputStream in = socket.getInputStream();
//4.创建文件的输出流
FileOutputStream fos = new FileOutputStream(System.currentTimeMillis() + ".png");
//循环:一边读数据,一边写文件
byte[] bs = new byte[1024];
int len = 0;
while ((len = in.read(bs)) != -1) {
fos.write(bs, 0, len);
}
System.out.println("文件保存成功...");
//5.获取输出流
OutputStream out = socket.getOutputStream();
//6.给客户端回信息
out.write("您的图片我收到了,安息吧~~".getBytes());
System.out.println("消息回复成功...");
//7.释放资源
out.close();
fos.close();
in.close();
socket.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}).start();
}
//server.close();
//System.out.println("服务器关闭...");
}
}
BS架构模式
扩展,服务器扩展图片显示问题
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//1.创建服务器
ServerSocket server = new ServerSocket(12345);
System.out.println("服务器启动...");
//2.接收客户端
while (true) {
Socket socket = server.accept();
System.out.println("客户端来了..");
//3.获取输入流
InputStream in = socket.getInputStream();
//4.使用输入流的read方法,把浏览器发送过的数据读取出来
//我们现在只想读取,客户端要的那个文件
//a.只读第一行
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line = br.readLine();
//b.从中获取浏览器想要的那个文件名字
String[] splits = line.split(" ");
String fileName = splits[1].substring(1);
System.out.println("浏览器想要:" + fileName);
//5.把浏览器想要的文件,读取出来,发送给浏览器
FileInputStream fis = new FileInputStream(fileName);
OutputStream out = socket.getOutputStream();
byte[] bs = new byte[1024];
int len = 0;
out.write("HTTP/1.1 200 OK\r\n".getBytes());
out.write("Content-Type:text/html\r\n".getBytes());
out.write("\r\n".getBytes());
while ((len = fis.read(bs)) != -1) {
out.write(bs, 0, len);
}
//5.释放资源
in.close();
socket.close();
}
// server.close();
// System.out.println("服务器关闭..");
}
}
TCP协议下文件上传案例
什么叫上传: 客户端把其硬盘中文件,通过网络发送到服务器端,并保存到服务器的硬盘中
上传过程: a.客户端读取本地文件 b.通过输出流发送给服务器
c.服务器读取输入流数据 d.保存到服务器的本地
TCP协议下BS案例
我们不需要自己编写客户端,使用浏览器当过客户端,去访问服务器
访问时: 127.0.0.1:8888
other=================================
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
/*
需求:使用TCP协议实现客户端和服务端互相发送消息。
客户端发送一条消息,服务器读取之后,返回一条消息给客户端,客户端读取服务器返回的消息之后,又发送一条消息…循环执行,直到输入exit。
要求:
1. 消息内容通过键盘输入
2. 要求服务器端和客户端都使用字符流的方式发送和接收数据。
使用BufffferedReader方法readLine()读取一行数据。
使用BufffferedWriter方法write("字符串的数据")发送数据。
*/
public class Server {
public static void main(String[] args) throws IOException {
// 创建服务器端对象
ServerSocket serverSocket = new ServerSocket(7777);
// 获得socket对象
Socket socket = serverSocket.accept();
// 字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 键盘录入
Scanner scanner = new Scanner(System.in);
// 字符输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 循环
while(true){
// 接收客户端的数据
System.out.println("客户端说:" + br.readLine());
// 提示:
System.out.println("服务器说:");
String line = scanner.nextLine();
// 判断
if("exit".equals(line)){
break;
}
// 写出数据(服务器给客户端的相应数据!)
bw.write(line);
bw.newLine();
bw.flush();
}
socket.close();
serverSocket.close();
}
}
、、---
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
/*
需求:使用TCP协议实现客户端和服务端互相发送消息。
客户端发送一条消息,服务器读取之后,返回一条消息给客户端,客户端读取服务器返回的消息之后,又发送一条消息…循环执行,直到输入exit。
要求:
1. 消息内容通过键盘输入
2. 要求服务器端和客户端都使用字符流的方式发送和接收数据。
使用BufffferedReader方法readLine()读取一行数据。
使用BufffferedWriter方法write("字符串的数据")发送数据。
*/
public class Client {
public static void main(String[] args) throws IOException {
// 创建Scoket对象
Socket socket = new Socket("127.0.0.1",7777);
// 字符输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 键盘录入
Scanner scanner = new Scanner(System.in);
// 字符输入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 无限循环
while(true){
System.out.println("客户端说:");
// 数据来自键盘录入
String line = scanner.nextLine();
// 判断
if("exit".equals(line)){
// 结束循环
break;
}
// 发送数据(写出数据,客户端向服务器端发送请求的数据!)
bw.write(line);
// 换行
bw.newLine();
// 一定要flush
bw.flush();
// 读取来自服务器端响应的结果数据
System.out.println("服务器端说:" + br.readLine());
}
br.close();
bw.close();
socket.close();
}
}