——- android培训、java培训、期待与您交流! ———-
网络编程概述:
计算机网络:
是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,实现资源共享和信息传递的计算机系统;
网络编程:
就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换。
网络模型:
计算机网络之间以何种规则进行通信,就是网络模型研究问题;
网络模型一般指:
OSI参考模型: TCP/IP模型
应用层
表示层 应用层
会话层
传输层 传输层
网络层 网际层
数据链路层 主机至网络层
物理层
网络编程三要素:
A: IP地址
B:端口
C:协议
1.IP地址:
网络计算机的唯一标识别;计算机只能识别二进制的数据,所以我们的IP地址应该是一个二进制的数据。(点十分制):
B:IP地址的组成
IP地址 = 网络号码+主机地址
A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
C类IP地址:前三段号码为网络号码,剩下的一段号码为本地计算机的号码
特殊地址:
127.0.0.1 回环地址,可用于测试本机的网络是否有问题. ping 127.0.0.1
X.X.X.255 广播地址
X.X.X.0 网络地址
DOS命令 ipconfig:查看本机IP地址
xxx.xxx.xxx.0 网络地址
xxx.xxx.xxx.255 广播地址
A类 1.0.0.1---127.255.255.254 (1)10.X.X.X是私有地址(私有地址就是在互联网上不使用,而被用在局域网络中的地址) (2)127.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
2.端口:
物理端口 网卡口
逻辑端口
A:每个网络程序都会至少有一个逻辑端口;
B:用于标识进程的逻辑地址,不同进程的标识;
C:
端口号:
正在运行的程序的标识;
有效端口:0---65535,其中0—1024系统使用或保留端口;
3..协议:
通信的规则:
Tcp:
建立连接,形成传输的数据通道;
在连接中进行大数据量传输:
通过三次握手完成链接,是可靠协议;
必须建立连接,效率稍低;
UDP:把数据打包,
数据有限制不能超过64k,
不建立连接
速度快
不可靠
IntAddress:
如果一个类没有构造方法:
A:成员全部是静态的(Math,Arrays,Collection)
B: 单例设计模式:(Runtime)
C:类中有静态方法返回该类的对象(InetAddress)
Class Demo{
Private Demo() {}
Public static Demo getXxx(){
Return new Demo();
}
}
public static InetAddress getByName(String host)
根据主机名或者IP地址的字符串表示得到IP地址对象;
public String getHostName()
返回 IP 地址字符串(以文本表现形式
public String getHostAddress()
返回 IP 地址字符串(以文本表现形式)。
InetAddress address = InetAddress.getByName("ASUS-PC");
String name = address.getHostName();
String ip = address.getHostAddress();
System.out.println(name + "---- "+ip);
}
}
Socket
Socket套接字:
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识的标识符套接字。
Socket原理机制:
通信的两端都有Socket
网络通信其实就是Socket间的通信;
数据在两个Socket间通过IO传输;
UDP协议发送和接收数据:
1.UDP协议发送数据:
DatagramPacket
(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length
的包发送到指定主机上的指定端口号。
Public void send(Datagrampacket p):
/*
* UDP发送数据:
* A:创建发送端Socket对象
* B:创建数据,并把数据打包;
* C:调用Soket对象的发送方式发送数据
* D:释放资源;
*/
public static void main(String[] args) throws IOException {
//创建Socket对象
DatagramSocket ds = new DatagramSocket();
//创建数据,并把数据打包;
//DatagramPacket(byte[] buf, int length,InetAddress address, int port)
//创建数据:
byte[] bys="hello,happiness".getBytes();
int length =bys.length;
InetAddress address = InetAddress.getByName("ASUS-PC");
//端口:
int port= 10086;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
//调用Socket对象的发送方法发送数据;
ds.send(dp);
//释放资源
ds.close();
}
2.UDP接受数据:
/*
*UDP接收数据:
*A:创建接收端Socket对象
* B:创建一个数据包(接收容器);
* C:调用Soket对象的接收方式接收数据
* D:解析数据包,并显示在控制台;
* D:释放资源;
*/
//DatagramSocket(int port)
DatagramSocket ds =new DatagramSocket(10086);
//创建一个数据包(接收容器)
//DatagramPacket(byte[] buf , int length)
byte[] bys= new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
//调用Socket对象的接收方法接收数据
//public void receive(DatagramPacket p)
ds.receive(dp);//阻塞式
//解析数据包,并显示在控制台
//获取对方Ip
//public InetAddress g
byte[] by2= dp.getData();
int len = dp.getLength();
String s = new String(by2, 0,len);
System.out.println(s);
//释放资源
ds.close();
}
}
代码的优化:
发送端的代码:键盘录入数据发送:
/*
* 数据来自于键盘录入
* 键盘录入数据要自己控制录入结束。
*/
public class SendDemo {
public static void main(String[]args) throws IOException {
// 创建发送端的Socket对象
DatagramSocketds = new DatagramSocket();
// 封装键盘录入数据
BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));
Stringline = null;
while((line = br.readLine()) != null) {
if("886".equals(line)) {
break;
}
//创建数据并打包
byte[]bys = line.getBytes();
//DatagramPacket dp = new DatagramPacket(bys, bys.length,
//InetAddress.getByName("192.168.12.92"), 12345);
DatagramPacket dp = newDatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.12.255"),12345);
//发送数据
ds.send(dp);
}
// 释放资源
ds.close();
}
}
接收端的代码:
/*
* 多次启动接收端:
* java.net.BindException: Address already in use: Cannot bind
* 端口被占用。
*/
public class ReceiveDemo {
public static void main(String[]args) throws IOException {
// 创建接收端的Socket对象
DatagramSocketds = new DatagramSocket(12345);
while(true) {
//创建一个包裹
byte[]bys = new byte[1024];
DatagramPacketdp = new DatagramPacket(bys, bys.length);
//接收数据
ds.receive(dp);
//解析数据
Stringip = dp.getAddress().getHostAddress();
Strings = new String(dp.getData(), 0, dp.getLength());
System.out.println("from" + ip + " data is : " + s);
}
// 释放资源
// 接收端应该一直开着等待接收数据,是不需要关闭
//ds.close();
}
Tcp协议发送和接收数据:
TCP协议发送数据:
A:创建发送端的Socket对象;
这一步如果成功,就说明连接成功了。
B:获取输出流,写数据;
C:释放资源:
public static void main(String[] args) throws IOException, IOException {
//Socket s = newSocket(Inet4Address.getByName("127.0.0.1"),123456);
//创建发送端的Socket对象;
Socket s = new Socket("172.27.35.3", 1234);
//获取数据:
//public OutputStream getOutputStream();
OutputStream os= s.getOutputStream();
os.write("hello.tcp.我来了".getBytes());
//释放资源
s.close();
TCP服务端获取数据:
A:创建接收端的Socket对象;
B:监听客户端连接,返回一个对应的Socket对象
C:获取输入流,读取数据显示在控制台;
D:释放资源;
//创建接收端的Socket对象
// ServerSocket (intport);
ServerSocket ss = new ServerSocket(1234);
//监听客户端连接。返回一个对应的Socket对象
//public Socket accept()
Socket s = ss.accept();
//获取输入流,读取数据显示在控制台;
InputStream is =s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String str = new String(bys, 0 ,len);
System.out.println(len);
System.out.println(str);
服务器给客户端一个反馈案例;
客户端代码:
InetAddress Address =InetAddress.getByName("ASUS-PC");
String ip = Address.getHostAddress();
System.out.println("IP是:"+ip);
//创建socket对象
Socket ss= new Socket("127.0.0.1",2222);
//创建输出流对象:
OutputStream outs = ss.getOutputStream();
outs.write("hello,服务器".getBytes());
//获取输入流;
InputStream ins= ss.getInputStream();
byte[] bys= new byte[1024];
int len=ins.read(bys);
String str = new String(bys,0,len);
System.out.println(str);
ss.close();
}
服务端代码:
//创建服务器Socket对象
ServerSocket ss= new ServerSocket(2222);
//监听客户端的连接;
Socket s = ss.accept();//阻塞式
//获取输入流
InputStream in = s.getInputStream();
byte[] bys = new byte[1024];
int len= in.read(bys);
String server =new String(bys,0,len);
System.out.println("server"+ server);
//获取输出流:
OutputStream outs = s.getOutputStream();
outs.write("您好,客户端,数据已经收到".getBytes());
//释放资源
s.close();
}
客户端键盘录入服务器写到文本文件;
客户端代码:
//创建Socket对象
Socket ss= new Socket("127.0.0.1",1111);
//包装键盘流;
BufferedReader br= new BufferedReader(new InputStreamReader(System.in));
//通道流;
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
String line =null;
while((line =br.readLine())!=null){
if("over".equals(line)){
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
ss.close();
服务器端代码:
//创建ServerSocket对象
ServerSocket ss= new ServerSocket(1111);
FileWriter file =new FileWriter("ba.txt" );
//监听接收对象;
Socket s= ss.accept();
//创建流;
BufferedReader bufr = new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
// BufferedWriter bufw =new BufferedWriter(new OutputStreamWriter(newFileOutputStream("b.txt")));
String str;
while( ( str= bufr.readLine()) !=null){
bufw.write(str);
bufw.newLine();
bufw.flush();
}
bufw.close();
s.close();
TCP上传文本文件并给出反馈:
读取文本文件是可以以null作为接收结束信息的,但是呢,通道流中是不能这样结束的。
所以,服务器根本就不知道你结束了。而你还想服务器给你反馈。所以,就互相等待了。
如何解决呢?
A:在多写一天数据,告诉服务器,读取到这条数据说明我就结束,你也结束吧。
这样做可以解决问题,但是不好。
B:Socket对象提供了一种解决方案
Public void shutdownOutput()
客户端发送数据:
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader(
"InetAddressDemo.java"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义一个结束标记
// bw.write("over");
// bw.newLine();
// bw.flush();
//Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput();
// 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
客户端接收数据:
// 创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(11111);
// 监听客户端连接
Socket s = ss.accept();// 阻塞
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
// if("over".equals(line)){
// break;
// }
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();
}
Tcp协议上传图片给出反馈:
客户端:
public static void main(String[] args) throwsIOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 19191);
// 封装图片文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
"喜欢你.jpg"));
// 封装通道内的流
BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
s.shutdownOutput();
// 读取反馈
InputStream is = s.getInputStream();
byte[] bys2 = new byte[1024];
int len2 = is.read(bys2);
String client = new String(bys2, 0, len2);
System.out.println(client);
// 释放资源
bis.close();
s.close();
}
}
服务器端的代码:
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(19191);
// 监听客户端连接
Socket s = ss.accept();
// 封装通道内流
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
// 封装图片文件
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("mn.jpg"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
// 给一个反馈
OutputStream os = s.getOutputStream();
os.write("图片上传成功".getBytes());
bos.close();
s.close();
}
}
多个客户端上传到服务器:
客户端代码:
public static void main(String[] args) throwsIOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
// BufferedReader br = new BufferedReader(newFileReader(
// "InetAddressDemo.java"));
BufferedReader br = new BufferedReader(new FileReader(
"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();
}
// Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput();
// 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
}
服务器端代码:
public static void main(String[] args) throwsIOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
线程:
public class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件
// BufferedWriter bw = newBufferedWriter(new
// FileWriter("Copy.java"));
// 为了防止名称冲突
String newName = System.currentTimeMillis()+ ".java";
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
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();
}
}
}