第一讲 网络编程概述
1、网络模型:OSI参考模型和TCP/IP参考模型
应用层为:FTP和HTTP协议等,传输层为:UDP和TCP等,网际层为:IP。
2、网络通信三要素:IP地址,端口号,传输协议
A、IP地址
a、它是网络中的设备标识
b、不易记忆,可用主机名表示,两者存在映射关系
c、本机回环地址:127.0.0.1,主机名为:localhost。
IP地址:java中对应的是InetAddress类,存在于java.net包中。
InetAddress类:
(一)无构造函数,可通过getLocalHost()方法获取InetAddress对象,此方法是静态的,返回本类对象。
InetAddress i = InetAddress.getLocalHost();
(二)方法:
1)static InetAddress getByName(String host):获取指定主机的IP和主机名。(最好用ip地址去获取,主机名需要解析)
2)static InetAddress[] getAllByName(String host):在给定主机名的情况下,根据系统上配置的名称服务返回IP地址所组成的数组。返回对象不唯一时,用此方法。
3)String getHostAddress():返回IP地址字符串文本形式,以IP地址为主。
4)String getHostName():返回IP地址主机名。
(三)如何获取任意一台主机的IP地址对象:
1)功能:返回InetAddress对象
2)对于任意主机,需要指定传入主机名的参数
注意:如果IP地址和对应的主机名,这种映射关系没有在网络上,就不会解析成功,返回的还是指定的IP。
B、端口号:
a、用于标识进程的逻辑地址,不用进程的标识。
b、有效端口:0 ~65535,系统使用或保留的端口是:0~ 1024。
C、传输协议:
即通信规则,包含TCP和UDP协议
UDP
是面向无连接,明确了对方的端口,无论在不在网上,只管传输,不在就会丢失数据。只求速度,应用于网络视频会议和聊天等应用程序中。
协议特点:
a、面向无连接,即将数据及源和目的封装成数据包中,不建立链接的发送
b、每个数据包的大小限制在64K之内
c、因无连接,是不可靠的协议
d、不建立连接,速度快。
TCP
是面向连接的,必须连接成功才能传输数据,应用于下载等程序上
协议特点:
a、面向连接,在建立连接后,形成传输数据的通道
b、在连接中进行大数据量的传输
c、通过三次握手完成连接,是可靠的协议
d、必须建立连接,效率稍慢
三次握手:第一次本方发送请求,第二次对方确认连接,第三次本方再次确认连接成功。
3、通信的步骤:
1)找到IP地址
2)数据要发送到对象指定应用程序,为标识这些应用程序,所以给这些网络应用程序都用数字标识,为方便称呼这个数字,叫做端口,即逻辑端口。
3)定义通信规则,称之为协议。国际组织定义了通用协议,即TCP/IP。
注意:必须要有数字标识才能将数据发送到应用程序上。
UDP有发送端和接受端,有两大类,DatagramSocket、DatagramPacket
步骤:
(1)建立发送端和接收端(2)建立数据包
(3)调用Socket的接收发送方法
(4)关闭Socket
注意:发送端和接收端是两个独立的运行程序
UDP发送端演示
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为
length
的包发送到指定主机上的指定端口号。
public static void UDPsendDemo() throws IOException {
System.out.println("发送端");
/*
* 创建UDP传输的发送端:
* 1.建立UDP的Socket服务
* 2.将要发送的数据封装到数据包中
* 3.用UDP的Socket服务将数据包发送出去
* 4.关闭Socket服务
*/
//建立UDP的Socket服务,使用DatagramSocket对象
DatagramSocket ds = new DatagramSocket();
//不指定端口号,发送端,就是随机的
//数据封装成包
String str = "udp发送";
//使用DatagramPacket将数据封装到该对象的包中
byte[] by = str.getBytes();
DatagramPacket dp = new DatagramPacket(by,by.length,InetAddress.getByName("127.0.0.1"),6534);
//通过UDP的Socket服务将数据包发送出去,send方法
ds.send(dp);
ds.close();
}
UDP接收端演示
public static void UDPreceiveDemo() throws IOException {
//接受端
System.out.println("接收端");
/*
* 创建UDP传输的接收端:
* 1.建立UDP的Socket服务,因为要接收数据,必须要明确端口号
* 2.创建数据包,用于存储接收到的数据,以便于用数据包的方法解析这些数据
* 3.使用Socket服务的receive方法接收的数据存储到数据包中
* 4.通过数据包中的方法解析包中数据
* 5.关闭
*/z
//建立UDP的Socket服务,使用DatagramSocket对象
DatagramSocket ds = new DatagramSocket(6534);//接收端口6534
//创建数据包
byte[] buf = new byte[1024];
DatagramPacket dp = new DatagramPacket(buf, buf.length);
//使用接收方法将数据存储到数据包
ds.receive(dp);//注意该方法是阻塞式的
//使用数据包对象的方法,解析其中的数据,如:地址、端口、内容
String ip = dp.getAddress().getHostAddress();//获取ip地址字符串
int port = dp.getPort();//获取端口
String datatext = new String(dp.getData(),0,dp.getLength());//将数据封装成字符串对象
System.out.println("ip:"+ip+"port : "+port+"data:"+datatext);
//关闭
ds.close();
}</span>
基于多线程模拟简单的QQ聊天程序
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
class Receive implements Runnable{
private DatagramSocket ds;
public Receive(DatagramSocket ds){
this.ds = ds;
}
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();
int port = dp.getPort();
String datatext = new String(dp.getData(),0,dp.getLength());
if(datatext.equals("over")){
System.out.println("ip:"+ip+"port : "+port+"退出聊天室");
}
else{
System.out.println("ip:"+ip+"port : "+port+"data:"+datatext);
}
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
class Send implements Runnable{
private DatagramSocket ds;
public Send(DatagramSocket ds){
this.ds = ds;
}
public void run()
{
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = br.readLine())!=null){
byte[] buf = line.getBytes();
DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.255"),6534);
//IP的有效位是0-254,255是广播,也就是127.0.0,这一IP字段上所有存活的电脑都可以接收到我发的信息
ds.send(dp);
if("over".equals(line))break;
}
ds.close();
} catch (Exception e) {
// TODO: handle exception
}
}
}
public class Main {
public static void main(String[] args) throws IOException{
DatagramSocket dsend =new DatagramSocket();
DatagramSocket dr =new DatagramSocket(6534);
Send send = new Send(dsend);
Receive receive = new Receive(dr);
Thread t1 = new Thread(send);
Thread t2 = new Thread(receive);
t1.start(); t2.start();
}
}
2.TCP协议
TCP传输
Socket和ServerSocket
建立客户端和服务器端(两个独立的应用程序)
建立连接后,通过Socket中的IO流进行数据的传输
关闭Socket
TCP和UDP原理差不多,只是涉及的对象不一样
TCP客户端
Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口。
public static void TCPDemo() throws UnknownHostException, IOException {
/*
* TCP传输,客户端建立
* 1.建立TCP客户端socket服务,使用SOCKET对象(建议一创建就明确目的地,要连接的主机)
* 2.如果连接建立成功,就说明数据传输通道已建立
* 该通道就是SOCKET流,是底层建立好的,因为是流,所以有输入输出,其输入输出流对象,在SOCKET获取
* 通过getInputStream()和getOutputStream()来获取两个字节流
* 3.使用输出流,将数据写出(网络)
* 4.关闭
*/
//建立客户端SOCKET服务
Socket socket = new Socket("127.0.0.1",6534);//地址和端口号
//获取SOCKET流中的输出流
OutputStream os = socket.getOutputStream();
//使用输出流将指定的数据写出
os.write("tcp客户端发送信息".getBytes());
socket.close();
}
TCP服务端
public static void TEPserveDeno() throws IOException {
//服务端接收客户端发来的数据,并打印在控制台
/*
* 建立TCP服务端
* 1.建立TCP服务端Socket服务,通过ServerSocket对象
* 2.服务端必须对外提供端口,否则客户端无法连接
* 3.获取连接过来的客户端对象(重点)
* (比如拨打10086人工,一个客户,一个服务人员,客户的数据,客户自己最清楚)
* 4.通过客户端对象获取Socket流兑取客户端发来的数据并打印
* 5.关闭资源:关闭客户端,关闭服务端
*/
//常见服务端对象
ServerSocket ss = new ServerSocket(6534);
//获取连接过来的客户端对象
Socket so = ss.accept();//此方法用来获取客户端对象
String ip = so.getInetAddress().getHostAddress();
//通过Socket对象获取输入流,读取客户端发来的数据
InputStream in = so.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String str = new String(buf,0,len);
System.out.println("ip : "+ip+"server : "+str);
so.close();//服务端一般是不关闭的
}
注意:TCP和UDP不一样的是,必须先开启服务端,服务端不打开,客户端就无法访问,而UDP随意
第三讲 TCP协议练习
上传文本文件
public class Main {
public static void main(String[] args)throws IOException{
UpText_Client();
UpText_Server();
}
public static void UpText_Server() throws IOException {
ServerSocket ss = new ServerSocket(6534);
Socket socket = ss.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bw = new BufferedWriter(new FileWriter("c:\\server.txt"));
String line = null;
while((line = br.readLine())!=null){
//if("over".equals(line))break;//*
bw.write(line);
bw.newLine();//*
bw.flush();//*
}
PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
pw.println("上传成功");
br.close();
bw.close();
socket.close();
ss.close();
}
public static void UpText_Client() throws IOException {
Socket socket = new Socket("127.0.0.1",6534);
BufferedReader br = new BufferedReader(new FileReader("c:\\data.txt"));
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
String line = null;
while((line = br.readLine())!=null){
out.println(line);
}
//out.println("over");//*,开发的时候一般都是应用时间戳,做结束标记,先发给服务器一下时间戳,输入结束后,再发一次
//socket里有方法
socket.shutdownOutput();//告诉服务端数据写完了
//读取socket流
BufferedReader brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String string = brin.readLine();
System.out.println(string);
br.close();
socket.close();
}
}
*号处要注意,漏写容易造成,等待清理,客户端输入完毕后,服务端还在等待,不知道客户端已经输入完毕,阻塞,等待
第四讲 关于客户端服务端 && URL类 & URLConnection
常见的客户端和服务端
客户端:
浏览器:IE:弹窗口,猎豹:弹窗口,多标签,争强效果
服务端:
服务器:Tomcat:1.处理请求 2.给予应答
想让Tomcat为我们工作,那么java写的相关类类必须实现接口Serverlet
浏览器强大之处就在于解析能力,众多格式,都可以解析
服务端和客户端原理
自定义服务端:
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(9090);//Tomcat是8080
Socket socket = ss.accept();
InputStream in = socket.getInputStream();
System.out.println("ip : "+socket.getInetAddress().getHostAddress());
byte[] buf = new byte[1024];
int len = in.read(buf);
String text = new String(buf,0,len);
System.out.println(text);
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
out.println("你好");
socket.close();
ss.close();
}
使用已有的客户端IE,了解客户端给服务端发送的什么请求?
请求行: 请求方式 /1.html 请求资源路径:http协议版本
请求消息头:属性名:属性值
请求体
模拟一个浏览器获取信息
public static void main(String[] args) throws IOException {
Socket s = new Socket("192.168.1.1",8080);//向tomcat获取,浏览器信息
PrintWriter out = new PrintWriter(s.getOutputStream(),true);
out.println("GET / HTTP /.....");
out.println("....");
out.println("....");
out.println("....");
out.println("....");
out.println("....");
InputStream in = s.getInputStream();
byte[] buf = new byte[1024];
int len = in.read(buf);
String line = new String(buf,0,len);
System.out.println(line);//得到就是本地写的html代码
s.close();
}
得到的应答:
应答行:http的协议版本 应答状态码 应答状态描述信息
应答消息属性。 属性名: 属性值
应答体:->上述的html源码
PS:浏览器太难写了,所以众多厂商都是应用原有的IE的内核
类URL
类URL
代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询
每个URL都是URI,但不是每个URI都是URL
public static void URL_Demo() throws MalformedURLException {
String strurl = "http://127.0.0.1:8080/myhtml/1.html?name=wang";
//http://www.baidu.com/baidu?word=java,在百度地址栏搜索java
URL url = new URL(strurl);
System.out.println("Protocol:"+url.getProtocol());//获取主机协议
System.out.println("Host:"+url.getHost());//获取主机名
System.out.println("Port:"+url.getPort());//获取端口
System.out.println("File:"+url.getFile());//获取文件
System.out.println("Path:"+url.getPath());//获取路径部分
System.out.println("Query:"+url.getQuery());//获取查询部分
}
Protocol:httpHost:127.0.0.1
Port:8080
File:/myhtml/1.html?name=wang
Path:/myhtml/1.html
Query:name=wang
public static void URL_Demo() throws IOException {
String strurl = "http://127.0.0.1:8080/myhtml/1.html?name=wang";
URL url = new URL(strurl);
InputStream in = url.openStream();//打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。
/*
* 原理:
* openConnection()
* 返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。
* URLConnection conn = url.openConnection();
* System.out.println(connection);
* 底层封装完了关于url的http的解析方式,这个对象就是java内置的可以解析具体协议的对象+socket
* URLConnection类中
* 1.String str = conn.getHeaderField("Contend-Type");
* System.out.println(str);//应答一个文本类型的消息
* 然后就可以根据应答的结果,判断文本是何类型,根据指定的解析器,解析数据
* 实际上用的是Socket,加协议
* 2.InputStream in = conn.GetInputStream();同样得到1.html的应答体
*
* 所以url.openStream()的原理就是:
* URLConnection conn = url.openConnection();
* InputStream in = conn.GetInputStream();
*/
byte[] buf = new byte[1024];
int len = in.read(buf);
String str = new String(buf,0,len);
System.out.println(str);//得到1.html的应答体,url帮助解析成html源码
in.close();
}
域名解析
在浏览器输入网址访问一台主机所做的操作:
如输入http://61.135.169.125,可以直接连接此ip的主机,而我们一般是输入主机名:http:/www.baidu.ocm(百度主机对应的ip地址就是:61.135.169.125),那么此时浏览器做了神马操作呢?
也就是说如何通过主机名获取IP地址,从而连接到这台主机呢?这就需要将主机名翻译成IP地址,即域名解析:DNS
在进行访问的时候,会先在本地的hosts文件(c:\windows\system32\drivers\ext\host)中找对应的映射。若有,则直接返回请求;若无,则到公网的映射列表即DNS中找对应的映射,找到后,将主机名对应的IP地址返回给本机,本机通过这个IP地址找到对应的服务器。
示意图:
host应用:可屏蔽一些恶意网址,即将对应的映射关系写入hosts中,将IP地址改为本机的回环地址,那么会直接找到hosts,就不会将请求发送出去了。