网络编程
Java是Internet上的语言,提供了对网络应用程序的支持,就很容易开发常见的网络应用程序。
Java提供的网络类库,可以实现网络连接,联网的底层细节被隐藏在Java的本机安装系统中,由jvm进行控制,并且Java实现了一个跨平台的网络库,面对的是一个统一的网络编程环境。
网络基础
什么是网络?
把分步在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使更多的计算机可以方便地互相传递信息,共享数据
网路编程的目的
直接或间接的通过网络协议与其他计算机实现数据交换,进行通讯共享
网络通信
既然计算机可以实现共享数据,那如何去实现通信,如何指明要给哪台电脑传递信息?
可以通过IP和端口号,和网络通信协议
IP
IP是作为计算机唯一的标识
本机回环地址 127.0.0.1
IP的分类
第一种:IPV4和IPV6
IPV4:由4个字节组成,4个0-255的数字,以点隔开,比如 192.185.0.234
IPV6:由16个字节组成,8个无符号整数,用十六进制表示,每个整数用:冒号隔开,比如
324e:2345:1245:5326:12ea:1259:ce45:f325
第二种:万维网和局域网
万维网就是谁都可以访问,而局域网仅限于某公司或某学校内部使用
局域网的范围:192.168.0.0~192.168.255.255
端口号
端口号标识正在计算机上运行的程序,不同的程序有不同的端口号,端口号范围是0到65535之间的整数
端口的分类
公认端口:0~1023,被预先定义的服务通信占用,比如HTTP占用端口80,FTP(文件传输协议)占用端口21,Telnet(远程连接)占用端口23
注册端口:1024~49151 分配给用户进程或应用程序比如(Tomcat,占用端口8080,MySQL占用端口3306
私有端口:49152~65535
网络通信协议
OSI参考模型 :没有推广开,原因就是过于复杂和理想化
TCP/IP参考模型:国际标准
TCP/IP参考模型:应用层<-->传输层<--> 网络层 <-->物理+数据链路层
从左往右叫数据封装,从右往左叫数据拆封
Java网络API
InetAddress类
在java中 InetAddress类表示IP地址,两个子类 Inet4Address、Inet6Address
InetAddress类的对象包含主机地址的域名和IP地址
因为域名比较容易记忆,当在输入域名后,会通过域名服务器DNS,来把域名转换成IP地址,这一操作称为域名解析InetAddress类没有提构造器,而是提供了静态方法来实例化
常见方法
实例化方法:
getLocalHost() : 获取本地IP
getByName(String host) :指定IP
常用方法:
String getHostAddress() 返回IP地址
String getHostName() 返回该IP地址的主机名
boolean isReachable(int timeout) 测试是否能连接该地址
测试
public class InetAddressTest {
@Test
public void text1(){
try {
//如何实例化InetAddress getByName() getLocalHost()
//getByName(域名或IP地址)
InetAddress byName = InetAddress.getByName("127.0.0.1");
System.out.println(byName);
InetAddress byName1 = InetAddress.getByName("www.baidu.com");
System.out.println(byName1);
//getLocalHost():获取本机IP地址
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//getHostName():获取本机名
System.out.println(localHost.getHostName());
//getHostAddress():获取IP地址
System.out.println(localHost.getHostAddress());
//isReachable(int timeout) 判断是否可以连接
System.out.println(localHost.isReachable(1));
} catch (IOException e) {
e.printStackTrace();
}
}
}
网络通信协议
计算机网络中实现通信有一些约定,即通信协议,对速率,传输代码,代码结构,传输控制步骤,出错控制等制定标准
但是网络协议太复杂,因为涉及的内容很多,比如指定源地址和目标地址,加密解密等,
在指定协议时,把复杂成份的分解成一些简单的成份,再将它们组合起来,最常用的复合方式就是层次方式,即同层间可以通信,上一层可以调用下一层,不跨层处理,各层互不影响,利于系统的开发和扩展
传输层协议中,有两个重要的协议 TCP UDP
TCP :传输控制协议 transmission Control protocol
UDP:用户数据协议 user data protocol
TCP/IP是包括多个具有不同功能且互为关联的协议
IP协议是网络层的主要协议,支持网间互连的数据通信
TCP/IP 协议模型从更实用的角度出发,形成高效的四层体系结构
Socket套接字
IP和端口号组合在一起就是套接字
通信的连段都要有Socket,是两台机器间通信的端点,也就是说网络通信,就是Socket间的通信,Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
主动发起通信的应用程序叫客户端,等待通信请求的叫服务端
Socket分类
1.流套接字 :使用TCP提供可依赖的字节流服务
2.数据报套接字:使用UDP提供的数据报服务
构造器
Socket(InetAddress,端口号)创建流套接字,并连接到指定IP地址的指定端口号
Socket(String host,端口号)创建流套接字,并连接到指定域名的指定端口号
常用方法
getInputStream():返回该流套接字的输入流,可以用于接收网络消息
getOutputStream():返回该流套接字的输出流,可以用于发送网络消息
getInetAddress():返回该流套接字连接的IP地址,如果没有连接,返回null
getLocalAddress():返回本地地址
getPort():返回连接的端口号,如果没有连接套接字,则返回0;
getLocalPort() 返回本端的端口号,如果没有返回-1;
close()关闭套接字,关闭之后,不能再使用,只能重新创建新的套接字对象,关闭套接字后,该套接字的输入流和输出流也会关闭
shutdownInput():调用该方法,就不能再套接字的输入流中接收任何数据
shutdownOutput():禁用套接字的输出流,调用该方法后不能通过套接字的输出流发送任何数据
基于Socket的TCP编程
1.创建Socket对象
2.打开连接到Socket的输入、输出流
3.对Socket进行读、写操作
4.关闭Socket服务器和客户端
服务器通过ServerSocket(端口号)构造器 创建一个服务器端套接字,用于监听客户端的请求
然后调用accept()监听连接请求,如果客户端请求连接,则接受连接,返回通信
套接字对象。
调用该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出
流和输入流,开始网络数据的发送和接收。
关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。
测试
public class SocketTest {
@Test //建立客户端
public void text1(){
Socket so = null;
OutputStream ops = null;
try {
//1.创建对象,指定IPdi地址和端口号
InetAddress ia = InetAddress.getByName("指定IP");
so = new Socket(ia,45723);
//2.输入或输出
ops = so.getOutputStream();
ops.write("客户端发送数据".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(ops!=null){
try {
ops.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(so!=null){}
try {
so.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Test //建立服务端
public void text2(){
ServerSocket sso = null;
Socket accept = null;
InputStream is = null;
BufferedInputStream bis = null;
ByteArrayOutputStream bos = null;
try {
//1.调用ServerSocket(端口号)构造器:用于监听客户端的请求
sso = new ServerSocket(45723);
//2.调用accept()方法,监听连接请求
accept = sso.accept();
//3.调用输入输出方法
is = accept.getInputStream();
bis = new BufferedInputStream(is);
bos = new ByteArrayOutputStream();
byte[] bytes = new byte[10];
int data;
while((data = bis.read(bytes))!=-1){
bos.write(bytes,0,data);
}
System.out.println(bos.toString());
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(accept!=null){
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(sso!=null){
try {
sso.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
TCP练习
客户端发送文件给服务端,服务端将文件保存在本地,然后服务器给客户端反馈
public class TCPTest{
@Test //客户端
public void text(){
Socket so = null;
OutputStream os = null;
FileInputStream fis = null;
BufferedInputStream bos = null;
try {
so = new Socket(InetAddress.getByName("127.0.0.1"),23654);
os = so.getOutputStream();
fis = new FileInputStream("D:\\IO\\IO3\\wdm2.jpg");
bos = new BufferedInputStream(fis);
byte[] bytes = new byte[1024];
int data;
while((data = bos.read(bytes))!=-1){
os.write(bytes,0,data);
}
so.shutdownOutput();
InputStream is = so.getInputStream();
ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
byte[] bytes1 = new byte[10];
int len;
while((len = is.read(bytes1))!=-1){
bos1.write(bytes1,0,len);
}
System.out.println(bos1.toString());
bos1.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos !=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis !=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(os !=null){
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(so !=null){
try{
so.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test //服务端
public void text1(){
ServerSocket sso = null;
Socket accept = null;
InputStream is = null;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
try {
sso = new ServerSocket(23654);
accept = sso.accept();
is = accept.getInputStream();
fos = new FileOutputStream("D:\\IO\\IO3\\wdm.jpg");
bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[1024];
int data;
while((data = is.read(bytes))!=-1){
bos.write(bytes,0,data);
}
//
OutputStream os = accept.getOutputStream();
os.write("发送成功".getBytes());
os.close();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(is!=null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(accept!=null){
try {
accept.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(sso!=null){
try {
sso.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
UDP
DatagramSocket 和 DatagramPacket 类实现了基于 UDP 协议网络程序
UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证
UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP
地址和端口号以及接收端的IP地址和端口号。
UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和
接收方的连接
主要步骤:
1. DatagramSocket与DatagramPacket
2. 建立发送端,接收端
3. 建立数据包
4. 调用Socket的发送、接收方法
5. 关闭Socket
DatagramSocket类的常用方法
public DatagramSocket(int port)创建数据报套接字并将其绑定到本地主机上的指定端口。套接字将被绑定到通配符地址,IP 地址由内核来选择。
public DatagramSocket(int port,InetAddress laddr)创建数据报套接字,将其绑定到指定的本地地址。本地端口必须在 0 到 65535 之间(包括两者)。如果 IP 地址为 0.0.0.0,套接字将被绑定到通配符地址,IP 地址由内核选择。
public void close() 关闭此数据报套接字。
public void send(DatagramPacket p)从此套接字发送数据报DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
public void receive(DatagramPacket p)从此套接字接收数据报包。当此方法返回时,DatagramPacket
的缓冲区填充了接收的数据。数据报包也包含发送方的 IP 地址和发送方机器上的端口号。 此方法
在接收到数据报前一直阻塞。数据报包对象的 length 字段包含所接收信息的长度。如果信息比包的长度长,该信息将被截短。
public InetAddress getLocalAddress()获取套接字绑定的本地地址。
public int getLocalPort()返回此套接字绑定的本地主机上的端口号。
public InetAddress getInetAddress()返回此套接字连接的地址。如果套接字未连接,则返回 null。
public int getPort()返回此套接字的端口。如果套接字未连接,则返回 -1。
DatagramPacket类的常用方法
public DatagramPacket(byte[] buf,int length)构造 DatagramPacket,用来接收长
度为 length 的数据包。 length 参数必须小于等于 buf.length。
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。length参数必须小于等于 buf.length。
public InetAddress getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
public int getPort()返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
public byte[] getData()返回数据缓冲区。接收到的或将要发送的数据从缓冲区中的偏移量 offset 处开始,持续 length 长度。
public int getLength()返回将要发送或接收到的数据的长度。
测试
public class UDPTest {
//发送端
@Test
public void sender(){
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
String str = "发送到接收端";
byte[] data = str.getBytes();
InetAddress inet = InetAddress.getLocalHost();
DatagramPacket packet = new DatagramPacket(data,0,data.length,inet,9090);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
} finally {
if(socket !=null){
socket.close();
}
}
}
//接收端
@Test
public void receiver(){
DatagramSocket socket = null;
try {
socket = new DatagramSocket(9090);
byte[] buffer = new byte[100];
DatagramPacket packet = new DatagramPacket(buffer,0,buffer.length);
socket.receive(packet);
System.out.println(new String(packet.getData(),0,packet.getLength()));
} catch (IOException e) {
e.printStackTrace();
} finally {
if(socket !=null){
socket.close();
}
}
}
}
URL编程
URL(Uniform Resource Locator):统一资源定位符,它表示 Internet上某一资源的地址
它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。
URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
构造器
public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象
public URL(URL context, String spec):通过URL对象和相对路径构造一个 URL 对象
public URL(String 协议,String host, String file);
public URL(String 协议,String host,int 端口号, String file);
方法
public String getProtocol() 获取该URL的协议名
public String getHost() 获取该URL的主机名
public String getPort() 获取该URL的端口号
public String getPath() 获取该URL的文件路径
public String getFile() 获取该URL的文件名
public String getQuery() 获取该URL的查询名
测试
public class URLTest {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:8080/examples/beauty.jpg?username=Tom");
//public String getProtocol() 获取该URL的协议名
System.out.println(url.getProtocol());
//public String getHost() 获取该URL的主机名
System.out.println(url.getHost());
//public String getPort() 获取该URL的端口号
System.out.println(url.getPort());
//public String getPath() 获取该URL的文件路径
System.out.println(url.getPath());
//public String getFile() 获取该URL的文件名
System.out.println(url.getFile());
//public String getQuery() 获取该URL的查询名
System.out.println(url.getQuery());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
针对HTTP协议的URLConnection
URL的方法 openStream():能从网络上读取数据
如果要向服务器端程序发送数据,则必须先与URL建立连接,然后才能对其进行读写,需要URLConnection
URLConnection:表示到URL所引用的远程对象的连接。当与一个URL建立连接时,需要通过URL对象.openConnection()生成对应的URLConnection对象
URLConnection常用方法
URLConnection常用方法
public Object getContent( ) throws IOException
public int getContentLength( )
public String getContentType( )
public long getDate( )
public long getLastModified( )
public InputStream getInputStream( )throws IOException
public OutputSteram getOutputStream( )throws IOException
本人是Java初学者,水平有限,本文章中如果有不对的地方,麻烦您能指出来。向您表示感谢。
5710

被折叠的 条评论
为什么被折叠?



