1. 网络编程要素:
- 如何定位到网络上的一台或多台主机 IP地址和端口号
- 找到后如何通信 TCP/UDP
- JAVA,万物皆对象,去找相应的类
2. IP地址
ip地址的包: InetAddress
- 唯一定位一台网络上的计算机
- 本机localhost地址: 127.0.0.1
- ip地址分类:
- IPV4/IPV6
- IPV4
- IPV6
- 公网-私网
- ABCD类地址
- 192.168.xxx.xxx, 给组织内部使用
3. InetAddress包
没有构造函数,只能通过静态方法返回对象
直接查看java文档,获取本机地址/域名地址等,
得到的返回值为一个对象,获取他们的信息
InetAddress localhost = InetAddress.getLocalHost();
localhost.getAddress();
localhost.getcanonicalHostName();
localhost.getHostAddress();
localhost.getHostName();
4. 端口
端口表示计算机上一个程序的进程
- 不同的进程有不同的端口号,用来区分软件
- 端口被规定为0--65535
- TCP/UDP个有65536个,TCP和UDP都有端口80,并且可以同时使用
- 端口分类:
- 公有端口:0--1023
- HTTP 80, HTTPS 443
- FTP 21, Telent 23
- 程序注册端口(分配给用户或程序): 1024--49151
- Tomcat: 8080
- MySql: 3306
- Oracle: 1521
- 动态/私有: 49152-65535(不常用)
常用的Dos命令:
netstat -ano # 查看所有的端口
netstat -ano | findstr 80 #查看指定的端口(|为过滤的意思,把后面的条件带入前面去查找)
tasklist | findstr 8696 # 查看指定端口的进程(去任务管理器查看到PID之后去找)
本机host文件目录: C:\Windows\System32\drivers\etc
InetSocketAddress(ip, port)//有构造方法,可以被调用
//同样的方法返回端口号,ip地址,hostname等
5. 通信协议
TCP:用户传输协议,UDP:用户数据包协议,IP:网络互联协议
- TCP
- 连接,稳定
- 三次握手,四次挥手
连接--断开流程
A:瞅啥
B:瞅你咋地
A:干一场
A:我要断开了
B: 我知道你要断开了
B: 你真的断开了吗
A:我真的断开了
- 客户端,服务端
- 传输完成,释放连接,效率低
- UDP
- 不连接,不稳定
- 客户端,服务端,没有明确的界限
- 不管有没有准备好,都发过来
6. TCP通信
- 客户端:
- 连接服务器 Socket
- 发送消息(IO流)
- 服务端:
- 建立服务端口ServerSocket
- 等待用户连接 accept
- 接受用户消息(IO流)
//客户端代码:
public class TcpClientDemo01 {
public static void main(String[] args){
InetAddress ServerIP = null;
Socket socket = null;
OutputStream os = null;
try {
//1. 要知道服务其的地址和端口号
ServerIP = InetAddress.getByName("127.0.0.1");
int port = 9999;
//2. 创建socket通信
socket = new Socket(ServerIP, port);
//3. 连接完成后,发送IO流
os = socket.getOutputStream();
os.write("whats the fuck".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
finally {
if(os!= null) {
try {
os.close();
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}
}
//服务器端代码:
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket =null;
Socket socket =null;
InputStream is =null;
ByteArrayOutputStream baos =null;
try {
//1. 建立客户端要被连接的IP地址和端口号
serverSocket = new ServerSocket(9999);
//2. 等待客户端连接
socket = serverSocket.accept();
//3. 读取IO流
is = socket.getInputStream();
//输入流可能乱码,为防止,套接一个输出流,C输出,S输入,套接一个头输出
baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];//定义缓冲区
int len;
while((len = is.read(buffer))!=-1){//获得buffer的每一个位置
baos.write(buffer, 0, len-1);
}
System.out.println(baos.toString());
//finally里面关闭流等管道操作
} catch (IOException e) {
e.printStackTrace();
}finally {
if(baos != null) {
try {
baos.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
7. TCP文件传输(确定传输完成时间)管道判断
client:! 文件在module下面,不在src目录下面, 在src上一级
public class TcpClient {
public static void main(String[] args) throws Exception{
//1.创建socket通信
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//2. 读入文件,写出流
File test = new File("test.jpg");
FileInputStream fis = new FileInputStream(test);
OutputStream fos = socket.getOutputStream();
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer, 0, len);
}
//3. socket通知服务器流写出结束
//通知服务器发送完成是由socket进行的,不是output流
socket.shutdownOutput();
//4. 建立输入流,等待服务器接收结束的通知
InputStream fDidDown = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while((len2 = fDidDown.read(buffer2))!= -1){
baos.write(buffer2, 0, len2);
}
System.out.println(baos.toString());
//关闭
baos.close();
fDidDown.close();
fos.close();
fis.close();
socket.close();
}
}
server:
public class TcpServer {
public static void main(String[] args) throws Exception {
//1. 创建服务并监听
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
//2. 接收输入并保存文件
InputStream is = socket.getInputStream();
OutputStream fout = new FileOutputStream(new File("receive.jpg"));
byte[] buffer = new byte[1024];
int len;
while((len = is.read(buffer)) != -1){
fout.write(buffer, 0, len);
}
//3. 输出流通知客户端输出完毕
OutputStream fHaveDone = socket.getOutputStream();
fHaveDone.write("文件接收完成".getBytes());
//关闭
fHaveDone.close();
fout.close();
is.close();
socket.close();
serverSocket.close();
}
}
8. Tomcat
tomcat文件目录启动start, 配置文件修改,项目位置:webapps/root
9. UDP通信
用到两个包: DatagramSocket, DatagramPacket
重点:datagramPacket的构造方法,发送端五个参数,接收端3个参数
sender:
- 建立socket连接 2. 新建一个数据包 3. 发送 4. 关闭socket通信
public class UdpSender {
public static void main(String[] args) throws IOException {
//1. 建立一个socket
DatagramSocket socket = new DatagramSocket();
//2. 新建一个包
String Msg = "a UDP packet";
byte[] Msg_Byte = Msg.getBytes();
DatagramPacket dataPacket = new DatagramPacket(Msg_Byte, 0,
Msg_Byte.length, InetAddress.getByName("127.0.0.1"), 9999);
//3. 发送包
socket.send(dataPacket);
//4. 关闭socket
socket.close();
}
}
receiver:
- 提供通信 2. 接收数据 3. 操作数据 4. 关闭socket通信
public class UdpReceiver {
public static void main(String[] args) throws IOException {
//1. 提供服务
DatagramSocket socket = new DatagramSocket(9999);
//2. 接收数据包
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(datagramPacket);
//3. 操作数据
System.out.println(new String(datagramPacket.getData(), 0, datagramPacket.getData().length));
//4. 关闭socket
socket.close();
}
}
10. UDP 聊天实现
低版本: sender可以一直从键盘读取,receiver 可以一直接收
Sender:
public class Sender {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(9999);//本地端口号
while(true){
//InputStreamReader参数是键盘输入,把InputStream给bufferedReader, 然后读取下一行
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
String Msg = bufferedReader.readLine();//获取下一个输入
DatagramPacket datagramPacket = new DatagramPacket(//新建包,要连接的Socket在这里打包
Msg.getBytes(), 0, Msg.getBytes().length, new InetSocketAddress("localhost", 9998));
socket.send(datagramPacket);//发送
if (Msg.equals("bye")){
break;
}
}
socket.close();
System.out.println("聊天结束");
}
}
Receiver:
public class Receiver {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9998);//本地端口号
while(true){
//接收输入
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(datagramPacket);
//把输入转换为String
String Msg_output = new String(datagramPacket.getData(), 0, datagramPacket.getData().length);
System.out.println(Msg_output);
if (Msg_output.equals("bye")){//有问题不能实现
break;
}
}
System.out.println("聊天结束");
socket.close();
}
}
11. 多线程UDP咨询窗口
Java UPD的多线程在线咨询聊天窗口的实现
先写功能块,写一个发送线程和接收线程,( 就是重构,抽取特征,构建成类)
然后创建两个用户,实现这两个方法
Sender
public class Sender implements Runnable{
private int fromPort;
private String toIP;
private int toPort;
DatagramSocket socket;
BufferedReader bufferedReader;
public Sender(int fromPort, String toIP, int toPort) {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try{
socket = new DatagramSocket(fromPort);
bufferedReader = new BufferedReader(new InputStreamReader(System.in));
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while(true){
String Msg = null;
try {
Msg = bufferedReader.readLine();
DatagramPacket datagramPacket = new DatagramPacket(
Msg.getBytes(), 0, Msg.getBytes().length, new InetSocketAddress(toIP, toPort));
socket.send(datagramPacket);
if (Msg.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
System.out.println("聊天结束");
}
}
Receiver
public class Receiver implements Runnable {
DatagramSocket socket;
private int myPort;
public Receiver(int myPort) {
this.myPort = myPort;
try{
socket = new DatagramSocket(myPort);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while(true){
byte[] buffer = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(buffer, 0, buffer.length);
try {
socket.receive(datagramPacket);
String Msg_output = new String(datagramPacket.getData(), 0, datagramPacket.getData().length);
int FromPort = datagramPacket.getPort();
System.out.println("["+FromPort + "]" + Msg_output);
if (Msg_output.equals("bye")){//又问题不能实现
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("聊天结束");
socket.close();
}
}
User1
public class User1 {
public static void main(String[] args) {
new Thread(new Sender(9991,"localhost",10002)).start();
new Thread(new Receiver(10001)).start();
}
}
User2
public class User2 {
public static void main(String[] args) {
new Thread(new Sender(9992,"localhost",10001)).start();
new Thread(new Receiver(10002)).start();
}
}
12. URL
统一资源定位符:
5部分组成:
#有五部分组成:
协议//:ip地址:端口/项目名称/资源
URL rul = new URL("http://localhost:8080/helloworld/index.jsp?username=kk&password=123");
//很多方法
url.getHost();getProtocol();...
通过URL类下载东西
public class UrlDownload {
public static void main(String[] args) throws IOException {
//下载地址
URL url = new URL("http:loaclhost:8080/projectname/file.txt");
//连接到这个资源
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
//获得输入流,写到本地
InputStream inputStream = httpURLConnection.getInputStream();
FileOutputStream fos = new FileOutputStream("download.txt");
byte[] buffer = new byte[1024];
int len;
while((len = inputStream.read(buffer))!=-1){
fos.write(buffer, 0, len);
}
fos.close();
inputStream.close();
httpURLConnection.disconnect();//断开连接
}
}
(审查元素,去下载收费歌曲)