文章目录
一、网络编程
1、网络编程的三要素:
a) IP地址:网络中计算机的唯一标识
i. 常用的Dos命令
1. ipconfig:查看本机的IP地址
2. ping IP地址:测试本机与指定IP地址的通信
ii. IP地址的分类
A、1.0.0.1—127.255.255.254 10.X.X.X私有地址(私有地址:互联网上不使用,仅局域网使用)
第一号段为网络号段,后三段为主机号段
B、128.0.0.1—191.255.255.254 172.16.0.0—172.31.255.255私有地址 169.254.X.X保留地址
前两号段为网络号段,后两段为主机号段
C、192.0.0.1—223.255.255.254 192.168.X.X私有地址
前三号段为网络号段,最后一段为主机号段
D、224.0.0.1—239.255.255.254
E、240.0.0.1—247.255.255.254
iii. 特殊IP地址
1. 127.0.0.1 回环地址(表示本机)
2. X.X.X.255 广播地址
3. X.X.X.0 网络地址
b) 端口:
i. 物理端口:网卡口
ii. 逻辑端口:正在运行程序的标识
有效端口:0~65535 系统端口0~1024
c) 协议:
i. UDP:将数据源和目的地封装成数据包,不需要建立连接,每个数据报的大小限制在64k;
因无连接,属于不可靠协议,但运行速度快
ii. TCP:先建立连接,形成传输数据的通道,可以在连接中进行大量数据传输,
通过三次握手完成连接,是可靠协议,效率稍低
2. InetAddress类
表示互联网协议的IP地址
a) 此类无构造方法
如果一个类无构造方法:
i. 成员全部是静态的(Math,Arrays,Collections)
ii. 单例设计模式(Runtime)
iii. 类中有静态方法,返回该类的对象(InetAddress类)
b) 成员方法
i. public static InetAddress getByName(String host)
根据主机名或者IP地址的字符串表达形式获取IP地址对象
ii. public String getHostName() 根据IP地址对象获取主机名
iii. public String getHostAdderess() 根据IP地址对象获取IP地址
3. Socket:网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字
a) 原理机制
i. 通信两端都有Socket
ii. 网络通信其实就是Socket间的通信
iii. 数据在两个Socket之间通过IO传输
4. UDP协议
UDP协议中的Socket对象是DatagramSocket对象
a) 发送数据
i. 创建发送端Socket对象
ii. 创建数据,并将数据打包
数据包构造方法:public DatagramPacket(byte [] buf, int length, InetAddress address, int port)
buf为数据数组,length为数据长度,address为数据IP地址,port为数据端口
iii. 调用Socket对象的发送方法来发送数据包
public void send(DatagramPacket p)
iv. 释放资源
b) 接收数据
i. 创建接收端Socket对象(创建对象时需要指定端口号)
ii. 创建一个数据包(接收容器)
数据包构造方法public DatagramPacket(byte [] buf, int length)
iii. 调用Socket对象的接收方法接收数据
public void receive(DatagramPacket p)
iv. 解析数据
public byte [] getData() 获取数据缓冲区
public int getLength() 获取数据的实际长度
public InetAddress getAddress() 获取数据发送端的IP地址对象
v. 释放资源
c) 下面给出了传输实例
5. TCP协议
a) 发送
i. 创建TCP客户端Socket对象
ii. 获取输出流,写数据
iii. 释放资源
b) 接收
i. 创建服务器端ServerSocket对象
ii. 监听客户端连接
iii. 获取输入流,读取数据
iv. 释放资源
二、程序实例
1、UDP协议 发送接收实例
发送端
package test01_UDP_ReceiveSend;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
*UDP发送数据
* i. 创建发送端Socket对象
* ii. 创建数据,并将数据打包
* 数据包构造方法:public DatagramPacket(byte [] buf,
* int length, InetAddress address, int port)
* buf为数据数组,length为数据长度,address为数据IP地址,port为数据端口
* iii.调用Socket对象的发送方法来发送数据包
* public void send(DatagramPacket p)
* iv. 释放资源
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建Socket对象
DatagramSocket ds=new DatagramSocket();
//创建数据并打包,包括数据数组、数据长度、接收端地址和接收端端口号
byte []bys="HelloWorld".getBytes();
DatagramPacket dp=new DatagramPacket(bys, 0, bys.length,
InetAddress.getByName("10.128.245.238"), 12345);
//发送数据
ds.send(dp);
//释放资源
ds.close();
}
}
接收端
package test01_UDP_ReceiveSend;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/*
* i. 创建接收端Socket对象(创建对象时需要指定端口号)
* ii. 创建一个数据包(接收容器)
* 数据包构造方法public DatagramPacket(byte [] buf, int length)
* iii. 调用Socket对象的接收方法接收数据
* public void receive(DatagramPacket p)
* iv. 解析数据
* public byte [] getData() 获取数据缓冲区
* public int getLength() 获取数据的实际长度
* public InetAddress getAddress() 获取数据发送端的IP地址对象
* v. 释放资源
* 多次启动会报错:
* java.net.BindException: Address already in use: Cannot bind
* 原因:
* 多次启动端口被占用
*/
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
//创建Socket对象
DatagramSocket ds=new DatagramSocket(12345);
//创建包裹
byte[] bys=new byte[1024];
DatagramPacket dp=new DatagramPacket(bys, bys.length);
//接收数据
ds.receive(dp);
//解析数据
String ip=dp.getAddress().getHostAddress();
String s=new String(dp.getData(), 0, dp.getLength());
System.out.println("ip:"+ip+" Data:"+s);
//释放资源
ds.close();
}
}
2、UDP协议 利用多线程实现自己和自己聊天的程序实例
测试代码
package test02_UDP_Chat;
import java.io.IOException;
import java.net.DatagramSocket;
/*
* 通过多线程实现聊天小程序
*/
public class ChatDemo {
public static void main(String[] args) throws IOException {
DatagramSocket dsSend =new DatagramSocket();
DatagramSocket dsReceive =new DatagramSocket(12345);
SendThread st=new SendThread(dsSend);
ReceiveThread rh=new ReceiveThread(dsReceive);
Thread t1=new Thread(st);
Thread t2=new Thread(rh);
t1.start();
t2.start();
}
}
利用线程实现接收端
package test02_UDP_Chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds=ds;
}
public void run() {
try {
while(true) {
byte []b=new byte[1024];
DatagramPacket dp=new DatagramPacket(b, b.length);
ds.receive(dp);
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(), 0, dp.getLength());
System.out.println("ip:"+ip+" Data:"+data);
//因为要持续接收所以不释放资源
//ds.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
利用线程实现发送端
package test02_UDP_Chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//发送端
public class SendThread implements Runnable {
private DatagramSocket ds;
public SendThread(DatagramSocket ds) {
this.ds=ds;
}
public void run() {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)) ;
String line=null;
try {
while((line=br.readLine()) !=null) {
//当接收到886时结束发送
if(line.equals("886")) {
break;
}
byte []b=line.getBytes();
//注意发送端端口号要和接收端端口号相同
DatagramPacket dp=new DatagramPacket(b, 0, b.length,
InetAddress.getByName("10.128.245.238"), 12345);
ds.send(dp);
}
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3、TCP协议 发送接收实例
发送端
package test03_TCP_ReceiveSend;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
* TCP协议的发送数据
* 1、创建发送端的Socket对象,这一步如果成功说明连接建立成功了。
* 2、获取输出流,写数据
* 3、释放资源
*/
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象,2种方法
//Socket(InetAddress address , int port)
//Socket(String host ,int port)
//Socket s=new Socket(InetAddress.getByName("10.128.245.238"), 12345);
Socket s=new Socket("10.128.245.238",12345);
//获取输出流,写数据
OutputStream os=s.getOutputStream();
os.write("HelloWorld,TCP".getBytes());
//获取输入流,当接收数据成功后服务器给的反馈
InputStream is =s.getInputStream();
byte []b=new byte[1024];
int len=is.read(b); //阻塞
String str=new String(b, 0, len);
System.out.println("client:"+str);
//释放资源
s.close();
}
}
接收端
package test03_TCP_ReceiveSend;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
* TCP协议接收数据:
* 1、创建接收端Socket对象
* 2、监听客户端连接,返回一个Socket对象
* 3、获取输入流,读取数据显示在控制台
* 4、释放资源
*/
public class ReceivedDemo {
public static void main(String[] args) throws IOException {
//创建发送端对象
//ServerSocket(int port)
ServerSocket ss = new ServerSocket(12345);
//监听客户端连接,返回一个Socket对象
//public Socket accept();
Socket s=ss.accept(); //阻塞
//获取输入流并将读取数据显示在控制台
InputStream is=s.getInputStream();
byte [] b= new byte[1024];
int len=is.read(b); //阻塞
String str=new String(b,0,len);
String ip=s.getInetAddress().getHostAddress();
System.out.println("Data:"+str+"IP:"+ip);
//获取输出流,接收到字节数据后需要给一个反馈
OutputStream os = s.getOutputStream();
os.write("服务器已接收数据".getBytes());
//释放资源
s.close();
ss.close();
}
}
4、TCP协议 发送接收文件实例
发送端
package test04_TCP_file;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
/*
* 将文件数据读入,并发送到服务器端
* 以字符串的形式,每次读取文件的一行内容并发送
*
* 加入反馈信息,结果没反应,原因:
* 读取文本文件时以null作为结束信息,但是传递信息时,null不会被传递,
* 所以服务器并不确定结束了,而客户端一直在等服务器给反馈,所以最终就互相等待了
*
* 解决;
* 1、再多写一条数据作为结束标志,当客户端读取到此数据时意味着客户端读取文件结束了,服务器端接收到结束标志时也结束运行
* 此方法有一个弊端,如果结束标志在文件中也存在,文件便会读取不全
* 2、Socket对象提供了一个终止功能,会通知服务器结束传送
* public void shutdownOutput() 关闭输出流
* public void shutdownInput() 关闭输入流
*/
public class ClientDemo {
public static void main(String[] args) throws IOException {
Socket s=new Socket("10.128.245.238",12345);
BufferedReader br=new BufferedReader(new FileReader("D:\\jee-2018-09\\Net\\src\\test01_UDP_ReceiveSend\\ReceiveDemo.java"));
BufferedWriter bw=new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//告诉服务器端传送结束
s.shutdownOutput();
BufferedReader brClient=new BufferedReader(
new InputStreamReader(s.getInputStream()));
String client=brClient.readLine();
System.out.println(client);
br.close();
s.close();
}
}
接收端
package test04_TCP_file;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
//接收客户端发送的数据,并存入到文件中
// 每次接收一行并以字符串的格式写入到文件中
public class ServerDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(12345);
Socket s=ss.accept();
BufferedWriter bw= new BufferedWriter(new FileWriter("a.txt"));
BufferedReader br=new BufferedReader(new InputStreamReader
(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
BufferedWriter bwServer=new BufferedWriter(new OutputStreamWriter
(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
bw.close();
s.close();
ss.close();
}
}
5、TCP协议 多线程实现一个服务器接入多个客户端实例
服务器端测试类
package test05_TCP_Thread;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(12345);
while(true) {
Socket s=ss.accept();
ServerThread st=new ServerThread(s);
new Thread(st).start();
}
}
}
多线程实现服务器端
package test05_TCP_Thread;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class ServerThread implements Runnable {
private Socket s;
public ServerThread(Socket s) {
this.s=s;
}
public void run() {
try {
//为了区别不同客户端发送的文件,服务器针对不同客户端采用不同的命名方式
String newName = System.currentTimeMillis()+".java";
BufferedWriter bw= new BufferedWriter(new FileWriter(newName));
BufferedReader br=new BufferedReader(new InputStreamReader
(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
//不论传输字节流还是字符流都要刷新一下以免最后的数据漏传
bw.flush();
}
BufferedWriter bwServer=new BufferedWriter(new OutputStreamWriter
(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
bw.close();
s.close();
}catch(IOException e){
e.printStackTrace();
}
}
}
客户端
package test05_TCP_Thread;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) throws IOException {
Socket s=new Socket("10.128.245.238",12345);
BufferedReader br=new BufferedReader(new FileReader("D:\\jee-2018-09\\Net\\src\\test01_UDP_ReceiveSend\\ReceiveDemo.java"));
BufferedWriter bw=new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
String line=null;
while((line=br.readLine())!=null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//告诉服务器端传送结束
s.shutdownOutput();
BufferedReader brClient=new BufferedReader(
new InputStreamReader(s.getInputStream()));
String client=brClient.readLine();
System.out.println(client);
br.close();
s.close();
}
}