黑马程序员-网络
2015-05-24 本文已影响158人
狼孩
-------android培训java培训期待与您交流!----------
1. 概述
网络编程的本质是两个设备之间的数据交换,在计算机网络中,设备主要指计算机。
- 网络模型
网络传输方式中所细致划分层次的一个传输模型。每个层次都有自己功能作用。
1. OSI参考模型
* 主要有七层定义:两个设备间通讯先会进行封装信息包的动作然后传给要传输的设备,接受设备在进行拆包动作对信息解析和接受。
2. TCP/IP参考模型
* 是对OSI模型的一个简化,分为四层。网络编程主要对应的是传输层和网际层。
* 传输层对应的协议:TCP和UDP。网际层为:IP协议。应用层为HTTP、FTP等等协议。
- 网络通讯要素
- IP地址:网络设备标识。本机回环IP地址:127.0.0.1或者localhost,也是默认。用途:可以测试网卡等。
- 端口:网络设备上应用程序的标识,此标识称作端口(逻辑端口),范围是0-65535任选,其中0-1024为系统使用或者保留端口。
- 传输协议:定义通信规则,此规则称为协议。常见的协议有:国际通用协议为:TCP/IP,UDP。
package com.sergio.Network;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* IP对象使用示例
* Created by Sergio on 2015-05-19.
*/
public class IPDemo {
public static void main(String[] args) {
InetAddress i = null;
InetAddress ia = null;
try {
i = InetAddress.getLocalHost();
System.out.println(i.toString());
System.out.println(i.getHostAddress());
System.out.println(i.getHostName());
//通过名称主机名来解析地址和名字。但是还是以ip地址为主
ia = InetAddress.getByName("www.baidu.com");
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
2. UDP和TCP
- UDP:
- 将数据及源和目的封装成数据包,不需要建立连接
- 每个数据报的大小限制在64k内,有个封包动作
- 因无连接,是不可靠协议
- 不需要建立连接,速度快
- 应用场景:聊天,视频,桌面共享等
- TCP:
- 建立连接,形成传输数据的通道
- 在连接中进行大数据量传输
- 通过三次握手完成连接,是可靠协议
- 必须建立连接,效率会稍低
- 应用场景:下载等
3. Socket
- Socket是为网络服务提供的一种机制
- 通信两端都有Socket
- 网络通信就是Socket间的通信
- 数据在两个Socket间通过IO传输
4. UDP应用
- 对应的对象:DatagramSocket与DatagramPacket
- 发送数据的步骤:
* 1. 建立udp socket服务
* 2. 提供数据,并将数据封装到数据包中
* 3. 通过socket服务的发送功能,将数据包发出去
* 4。关闭资源
package com.sergio.Network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* UDP发送数据步骤:
* 1. 建立udp socket服务
* 2. 提供数据,并将数据封装到数据包中
* 3. 通过socket服务的发送功能,将数据包发出去
* 4。关闭资源
* Created by Sergio on 2015-05-19.
*/
public class UDPSendDataDemo {
public static void main(String[] args) throws Exception {
//socket服务建立
DatagramSocket ds = new DatagramSocket();
//提供数据
byte[] data = "udp send".getBytes();
//封装数据
DatagramPacket dp =
new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.123"), 10000);
//发送数据
ds.send(dp);
ds.close();
}
}
- 接收数据的步骤:
* 1. 定义UDP socket服务,通常会监听一个端口,用来接收该接受的应用程序
* 2. 定义数据包,用来存储接收到是字节数据,因为数据包对象中有更多功能可以提取字节数据的不同信息,
* 3. 通过socket服务的receive方法将接收到的数据存入一定以好数据包中,
* 4. 通过数据包对象的特有功能,将这些不同的数据取出。
package com.sergio.Network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
* UDP接受数据步骤:
* 1. 定义UDP socket服务,通常会监听一个端口,用来接收该接受的应用程序
* 2. 定义数据包,用来存储接收到是字节数据,因为数据包对象中有更多功能可以提取字节数据的不同信息,
* 3. 通过socket服务的receive方法将接收到的数据存入一定以好数据包中,
* 4. 通过数据包对象的特有功能,将这些不同的数据取出。
* Created by Sergio on 2015-05-19.
*/
public class UDPReceiveDataDemo {
public static void main(String[] args) throws Exception {
//创建udp socket服务,指定端口来接受该有的应用程序信息
DatagramSocket ds = new DatagramSocket(10000);
while (true) {
//定义数据包,用来存储接受到的数据包
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data, data.length);
//通过服务的receive方法将受到数据存入数据包中
ds.receive(dp);
//通过数据包的方法提取数据信息
String ip = dp.getAddress().getHostAddress();
//获取应有长度的数据内容
String data1 = new String(dp.getData(), 0, dp.getLength());
int port = dp.getPort();
System.out.println(data1 + ip + port);
}
}
}
- 练习聊天:
package com.sergio.Network;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.*;
/**
* 聊天程序
* Created by Sergio on 2015-05-19.
*/
public class ChatDemo {
public static void main(String[] args) throws Exception {
//创建发送和接受对象
DatagramSocket sendSocket = new DatagramSocket();
DatagramSocket receiveSocket = new DatagramSocket(10002);
//启动线程
new Thread(new Send(sendSocket)).start();
new Thread(new Receive(receiveSocket)).start();
}
}
//发送数据端线程
class Send implements Runnable {
private DatagramSocket ds;
public Send(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
//读取键盘录入并发送数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line))
break;
byte[] buf = line.getBytes();
DatagramPacket dp =
new DatagramPacket(buf, buf.length, InetAddress.getByName("192.168.1.123"), 10002);
ds.send(dp);
}
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//接受数据的线程
class Receive implements Runnable {
private DatagramSocket ds;
public Receive(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
//循环解析数据
while (true) {
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
String ip = dp.getAddress().getHostAddress();
String data = new String(dp.getData(), 0, dp.getLength());
System.out.println(ip + "::" + data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
5. TCP应用
- 对应的对象为:Socket和ServerSocket
- TCP分客户端和服务端。客户端对应的对象为Socket、服务端为:ServerSocket。
步骤: - 一. 客户端:
- 创建Socket服务,并指定要连接的主机和端口。
- 获取Socket流的中的输出流,将数据写到该流中,通过网络发送给服务端。
- 关闭Scoket。
- 二. 服务端:
- 建立服务端的Socket服务,ServerSocket();
- 获取连接过来的客户端对象,通过ServerSocket的accept方法连接,此方法是阻塞式的。
- 客户端如果发来数据,服务端需要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发来的数据。
- 关闭服务端(可选)。
- 注意:服务端没有输入输出流,主要是利用客户端对象的输出输入流来读取数据信息。
package com.sergio.Network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
/**
* 交互式客户端示例
* Created by Sergio on 2015-05-20.
*/
public class TCPClientDemo2 {
public static void main(String[] args) throws IOException {
//建立Socket服务,指定连接主机和端口号
Socket s = new Socket("192.168.1.123", 10004);
//获取Socket流中的输出流,并写入到该流中
OutputStream out = s.getOutputStream();
out.write("交互式信息发送".getBytes());
//交互部分代码输入,读取数据
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
System.out.println(new String(buf, 0, len));
s.close();
}
}
package com.sergio.Network;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 交互式服务端示例
* Created by Sergio on 2015-05-20.
*/
public class TCPServerDemo2 {
public static void main(String[] args) throws IOException {
//创建ServerSocket服务,并监听10004端口
ServerSocket ss = new ServerSocket(10004);
//通过accept方法获取客户端对象
Socket s = ss.accept();
//打印客户端的ip地址
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "连接进来");
//获取客户端的输入流,并读取数据
InputStream is = s.getInputStream();
byte[] buf = new byte[1024];
int len = is.read(buf);
System.out.println(new String(buf, 0, len));
//与客户端交互部分,写入数据
OutputStream out = s.getOutputStream();
out.write("服务端受到信息".getBytes());
s.close();
ss.close();
}
}
- 键盘录入数据服务端返回大写格式信息示例:
package com.sergio.Network;
import java.io.*;
import java.net.Socket;
/**
* 将客户端发送给服务端的字符转成大写。注意读取键盘录入数据的结束标记换行和回车符。
* Created by Sergio on 2015-05-20.
*/
public class TransClientDemo {
public static void main(String[] args) throws IOException {
Socket s = new Socket("192.168.1.123", 10005);
//定义读取键盘数据的流对象
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入到socket输出流,发送给服务端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//对上一句替换语句//PrintWriter pw = new PrintWriter(s.getOutputStream(), true);
//定义一个socket读取流,读取服务端返回的大写信息
BufferedReader brIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
if ("over".equals(line))
break;
bw.write(line);
//需要有个回车符结束标记
bw.newLine();
bw.flush();
//对上面三句的替换//pw.print(line);
//读取服务端返回的信息
String str = brIn.readLine();
System.out.println("server::" + str);
}
br.close();
s.close();
}
}
package com.sergio.Network;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 将客户端发送给服务端的字符转成大写。注意读取键盘录入数据的结束标记换行和回车符。
* Created by Sergio on 2015-05-20.
*/
public class TransServerDemo {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10005);
Socket s = ss.accept();
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "连接进来");
//读取socket读取流中的数据
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
//目的socket输出流将大小数据写入到socket暑促胡柳,并发送给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//PrintWriter pw = new PrintWriter(s.getOutputStream());
String line = null;
while ((line = br.readLine()) != null) {
//pw.print(line.toUpperCase());
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
s.close();
ss.close();
}
}
- 客户端登录服务器示例:
package com.sergio.Network;
import java.io.*;
import java.net.Socket;
/**
* 上传图片示例,客户端
* 步骤:1.服务端点,2.读取客户端已有的数据,3.通过Socket输出流将数据发给服务端,
* 4.读取服务端发聩信息,5.关闭
* Created by Sergio on 2015-05-22.
*/
public class UploadPicClient {
public static void main(String[] args) throws Exception {
//用来判断上传图片的上传要求
//为空
if (args.length != 1) {
System.out.println("请选择一个jpg格式的图片");
return;
}
File file = new File(args[0]);
if (file.exists() && file.isFile()) {
System.out.println("该文件有问题");
return;
}
if (!file.getName().endsWith(".jpg")) {
System.out.println("图片格式错误");
}
if (file.length() > 1024 * 1024 * 5) {
System.out.println("文件过大");
return;
}
Socket s = new Socket("192.168.1.123", 10008);
FileInputStream fis = new FileInputStream(file);
OutputStream out = s.getOutputStream();
byte[] buf = new byte[1024];
int len = 0;
while ((len = fis.read(buf)) != -1) {
out.write(buf, 0, len);
}
//告诉服务端数据已经传完
s.shutdownOutput();
//读取反馈的信息
InputStream in = s.getInputStream();
byte[] bufIn = new byte[1024];
int num = in.read(bufIn);
System.out.println(new String(bufIn, 0, num));
fis.close();
s.close();
}
}
package com.sergio.Network;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 上传图片示例,并发处理服务端
* Created by Sergio on 2015-05-22.
*/
public class UploadPicServer {
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(10008);
while (true) {
//获取客户端连接并监听地址和端口
Socket s = ss.accept();
//启动服务端并发处理的线程
new Thread(new PicThread(s)).start();
}
}
}
//服务端上传图片线程
class PicThread implements Runnable {
private Socket s;
PicThread(Socket s) {
this.s = s;
}
@Override
public void run() {
//用来重复上传图片计数
int count = 1;
String ip = s.getInetAddress().getHostAddress();
try {
System.out.println(ip + "连接进来了");
InputStream in = s.getInputStream();
//处理重复上传判断和处理
File file = new File(ip + "(" + (count) + ")" + ".jpg");
while (file.exists()) {
file = new File(ip + "(" + (count++) + ")" + ".jpg");
}
//读取图片
FileOutputStream fos = new FileOutputStream(file);
byte[] buf = new byte[1024];
int len = 0;
while ((len = in.read(buf)) != -1) {
fos.write(buf, 0, len);
}
//服务端回应客户端
OutputStream out = s.getOutputStream();
out.write("上传成功".getBytes());
fos.close();
s.close();
} catch (Exception e) {
throw new RuntimeException(ip + "上传失败");
}
}
}
URL和URLConnection
- URL是对底层传输层功能封装的对象。
- URLConnection相当于应用层对URL的功能封装,更简便。
1.URL
package com.sergio.Network;
import java.net.MalformedURLException;
import java.net.URL;
/**
* URL对象示例,对网址进行解析
* Created by Sergio on 2015-05-24.
*/
public class URLDemo {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("https://www.amazon.cn/clouddrive?sf=1&ref_=nav_Photos_Files");
System.out.println("协议" + url.getProtocol());
System.out.println("主机" + url.getHost());
System.out.println("端口" + url.getPort());
System.out.println("路径" + url.getPath());
System.out.println("文件" + url.getFile());
System.out.println("查询" + url.getQuery());
}
}
2.URLConnection
package com.sergio.Network;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
/**
* URLConnection对象使用,对连接解析并获取网页内容。
* Created by Sergio on 2015-05-24.
*/
public class URLConnectionDemo {
public static void main(String[] args) throws IOException {
URL url = new URL("https://www.amazon.cn.");
//应用层URLConnection对象封装,打开socket流
URLConnection conn = url.openConnection();
System.out.println(conn);
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
//打印获取到的数据信息
System.out.println(new String(buf, 0, len));
}
}