您的位置:首页 > 理论基础 > 计算机网络

java 自学日志 【十六】---网络编程

2013-05-13 15:17 393 查看
------android培训,java培训,期待与您交流------
网络编程:
网络编程是为了实现不同主机间的数据通信,要实现通讯,则要首先知道对方的IP和端口号,同时还要明确双方使用的通信规则(传输协议)。

IP地址,端口号和传输协议就是网络通讯的三要素:
①IP地址:是主机在网络上的地址,在网上的唯一标识,127.0.0.1是本地回环地址,可测试网卡是否损坏;
②端口号:数据要发送到对方指定的应用程序上,为了标识这些应用程序,用数字对其标识,这些数字就是端 口,或被称为逻辑端口;它并无物理实体与之对应;有效端口号从0~65535,其中0~1024是系统保留的 端口号;
一些常见的端口:浏览器:80 ; tomcat服务器:8080; mysql:3306;
③传输协议:要完成传输,还要遵守相同的通信协议,国际通用协议是 TCP/IP协议,既能用于局域网,也可以 用于广域网,除了TCP/IP,还有 UDP,FTP,HTTP等协议;

网络模型:主要有两个网络模型,一是OSI模型,一是TCP/IP模型;
OSI模型:从顶到底层 分别是: 应用层,表示层,会话层,传输层,网络层,数据链路层,物理层,分七层;
TCP/IP模型:为了简化,TCP/IP将OSI的应用层,表示层,会话层合并为应用层,数据链路层和物理层合并成 主机至网络层,所以它由
应用层,传输层,网际层,主机至网络层组成;

FTP,HTTP都在应用层,TCP,UDP在传输层,IP在网际层;
数据封包:数据从应用层开始,每经一层,都加入该层的标识信息,直到物理层,这个过程叫数据封包,之后 变成二进制数据从物理设备上输出;
数据拆包:去掉每层的标识信息,获取数据的过程就是拆包过程;

网络编程现阶段主要是在网际层,传输层,而javaweb开发主要是在应用层;
java中对各个层都创建了对象与之对应,以方便我们开发使用;

IP地址:是数字,由四段组成,如192.168.1.1,使用时不便于记忆,所以有与之对应的主机名,主机名与IP地址相对应;IP常用的方法如下:都在java。net包中;
InetAddress: getLocalHost();可获取主机名和本地地址;
getHostAddress():主机地址的字符串表现形式;
getHostName():获取主机名称;
如果网络获取主机名称,可能出现解析不成功的情况,那么IP地址就是主机名,getByName("")可通过给定主机名,获取主机的IP地址;
演示:
import java.net.*;
class  IPDemo
{
public static void main(String[] args) throws Exception
{
InetAddress i = InetAddress.getLocalHost();

System.out.println(i.toString());
System.out.println("address:"+i.getHostAddress());
System.out.println("name:"+i.getHostName());

InetAddress [] ia = InetAddress.getAllByName("www.renren.com");
for(InetAddress s : ia)
{
System.out.println(s.toString());
}

//System.out.println("address:"+ia.getHostAddress());
//System.out.println("name:"+ia.getHostName());
}
}


TCP/IP和UDP协议:两者都在传输层;
两者的区别:
①UDP:(User Datagram Protocol),用户数据报协议,是一种面向无连接的不可靠协议,它将数据源和目的封装成数据报包,在不需要建立连接的情况下就可实现传输,每个数据报包大小限制在64K内,特点是传输速度快;存在数据丢失的可能,主要应用于即时数据的传输,如QQ聊天程序,对话机,网络视频会议等;

②TCP:(Transmission Control Protocol),传输控制协议,它是面向连接的可靠的传输协议,通过三次握手的形式完成数据传输通道的连接,传输大量的数据,特点是速度相对较慢,适合对数据完整性要求高的程序,如下载应用程序;

Socket:(插座,套接字):
网络编程其实就是socket编程,它是为网络服务的一种机制,每个应用程序都有一个socket通信端点,可以把socket想象为每个应用程序的插座,通信的两端都有socket,数据在两个socket之间通过IO传输;

UDP传输:UDP两端是发送端和接受端;
DatagramSocekt:UDP传输专用的程序通信断电,既能发送也能接受;
DatagramPacket: 数据报包,封装了UDP传输的数据报包,里面可以设置发送目的地的IP地址,端口和内容;

广播地址:每个网段尾数为255的IP 地址,如192.168.1.255就是一个广播地址;
UDP代码演示:
/*
需求:通过Udp传输方式,将一段文字数据发送出去。
定义一个udp发送端。
思路:
1。建立UDPsocket服务。
2.提供数据,并将数据封装到数据包中。
3.通过socket服务的发送功能,将数据包发出去。
4.关闭资源。
*/
import java.net.*;
class UDPSend
{
public static void main(String[] args) throws Exception
{
//1.创建UDP服务,通过DatagramSocket对象。
DatagramSocket ds = new DatagramSocket(6666);
//2.确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port)
byte[] buf = "传输数据成功".getBytes();

DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.102"),10000);
//3.通过socket服务,将已有的数据包发送出去,通过send方法。
ds.send(dp);
//4.关闭资源。它使用了底层的资源,所以要关闭资源。
ds.close();
}
}
/*
需求;
定义一个应用程序,用于接收并处理数据。

定义udp接受端
思路:
1.定义socket服务,通常会监听一个端口,其实就是给这个接受网络应用程序定义一个数字标示。
方便与明确哪些数据过来该应用程序可以处理。
2.定义一个数据包,因为要存储要接受到的字节数据,
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3.通过socket服务的receive方法将收到的数据存入已定义的数据包中。
4.通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。
5.关闭资源。
*/
class UDPReceive
{
public static void main(String[] args) throws Exception
{
//1.创建udpsocket,建立端点。这里必须定义监听的端口,其实就是给网络应用程序定义数字标识。
DatagramSocket ds = new DatagramSocket(10000);
//2.定义数据包,用于存储数据。
byte[] buf = new byte[1024];

DatagramPacket dp = new DatagramPacket(buf,buf.length);
//3.通过服务的receive方法,将收到的数据存入到数据包中。
ds.receive(dp);
//4.获取数据包中的方法获取其中的数据
String ip = dp.getAddress().getHostAddress();

String data= new String(dp.getData(),0,dp.getLength());

int port = dp.getPort();

System.out.println(ip+"--"+data+"--"+port);

ds.close();
}
}
UDP代码演示2:
import java.net.*;
import java.io.*;
//键盘录入UDP传输
class  UDPSend2
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket();

BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

String line = null;

while((line=bufr.readLine())!=null)
{
if("886".equals(line))
break;
byte [] b = line.getBytes();
//192.168.1.255是这个网段的广播地址,用它就能实现局域网群聊。
DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("192.168.1.255"),10001);

ds.send(dp);
}
ds.close();
}
}

class UDPRece2
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds = new DatagramSocket(10001);

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);
}
}
}


利用UDP,编写一个聊天程序

有接受数据的部分,和发数据的部分。

这两部分需要同时执行。那就需要用到多线程技术。

一个线程控制收,一个线程控制发。

因为收和发动作是不一致的,所以要定义两个run方法,

而且run方法要封装到不同的类中。

import java.net.*;
import java.io.*;
class Send implements Runnable
{
private DatagramSocket ds;
//
public Send(DatagramSocket ds)
{
this.ds = ds;
}
public void run()
{
try
{
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line = bufr.readLine())!=null)
{
if("886".equals(line))
break;
byte[] buf =line.getBytes();
//把发送地址,设为广播地址,
InetAddress i = InetAddress.getByName("192.168.1.255");
DatagramPacket dp=
new DatagramPacket(buf,0,buf.length,i,10020);
ds.send(dp);
}
ds.close();

}
catch (Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}
class Rece implements Runnable
{
private DatagramSocket ds;
public Rece(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();
String data = new String(dp.getData(),0,dp.getLength());
System.out.println("ip:"+ip+" data:"+data);
}
}
catch (Exception e)
{
throw new RuntimeException("接受端失败");
}

}
}
class  ChatDemo
{
public static void main(String[] args) throws Exception
{
DatagramSocket sendSoket = new DatagramSocket();
DatagramSocket receSoket = new DatagramSocket(10020);

new Thread(new Send(sendSoket)).start();
new Thread(new Rece(receSoket)).start();

}
}


TCP传输:对应的是客户端和服务端

Socket:TCP传输客户端通信端点;
ServerSocket: TCP传输服务端端点;serversocket(port,backlog)这个构造函数中的backlog用于指定客户端的最大连接数;

因为TCP需要建立连接,所以socket客户端一建立就要指定服务端的IP和端口,而在服务端建立时,要设置监听的端口,TCP连接成功后,在客户端和服务端就会产生网络流,客户端提供对网络流进行读写的输入流和输出流对象,服务端操作网络流时,先获取客户端的socket对象,然后利用该socket的字节输入输出流进行读写操作,客户端和服务端进行多次交互时,注意阻塞式方法对程序的影响;

TCP代码演示一:

演示TCP传输。

1.tcp分客户端和服务端。

2.客户端对应的对象是Socket。

服务端对应的对象是SeverSocket


/*
客户端:
通过查阅Socket对象,发现在该对象建立时,就可以连接指定的主机。
因为TCP是面向连接的,所以在建立Socket服务时,就要有服务端存在,
并连接成功,形成通路后,在该通道进行数据的传输。

需求:给服务段发送一个文本数据。
步骤:
1.创建Socket服务,并指定要连接的主机和端口。
2.为了发送数据,应该获取Socket流中的输出流。
3.获取输出流后写入数据。
4.socket关闭客户端Socket服务,也就关闭了网络流资源。
*/
import java.net.*;
import java.io.*;
class  TCPClient
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.102",10086);

OutputStream out = s.getOutputStream();

out.write("i am coming!".getBytes());

s.close();
}
}
/*
难在服务端上。
需求:定义端点,接受数据,并打印在控制台上。

服务端:
1.建立服务端的Socket服务,通过SeverSocket();并监听一个端口。
2. 获取连接过了的客户端对象。
通过SeverSocket的accept方法。没有就会等,所以这个方法是阻塞式的。
3.客户端如果发过了数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过了的数据。并打印在控制台上。
4.关闭服务。(可选操作,服务端一般是一直开着的)。
*/
class TCPServer
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10086);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"......connect");

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

System.out.println(new String(buf,0,len));

s.close();
}
}


演示代码二:
演示tcp的传输的的客户端和服务端的互访。

需求:客户端给服务端发送数据,服务端收到数据后,给客户端反馈信息。


/*
客户端:
1.建立socket服务,指定要连接的主机和端口
1.获取Socket流中的输出流,将数据写入到该流中,通过网络发送给服务端。
3.获取socket流中的输入流,将服务端反馈的数据获取到,并打印,
4.关闭客户端资源。
*/
import java.io.*;
import java.net.*;
class  TCPC2
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.102",10010);

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();
}
}
class  TCPS2
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10010);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....connect");

InputStream in = s.getInputStream();

byte[] buf = new byte[1024];

int len = in.read(buf);

System.out.println(new String(buf,0,len));

OutputStream out = s.getOutputStream();

out.write("收到了".getBytes());

s.close();
}
}


演示代码三:
需求:建立一个文本转换服务器。

客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端。

而且,客户端可以不断的进行文本转换。当客户端输入over,转换就结束。

分析:

客户端:

既然是操作设备上的数据,那么就可以使用io技术,并按照IO的操作规律来思考。

源:键盘录入

目的:网络设备,也就是网络输出流,

而且操作的是文本数据,可以选择字符流。

步骤:

1,建立服务

2.获取键盘录入

3,将数据发给服务端。

4.获取服务端返回的大写数据。

5.结束,关闭资源。

都是文本数据,可以使用字符流进行操作。同时提高效率,要加入缓冲。


import java.io.*;
import java.net.*;
class TCPC3
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.102",10088);
//定义读取键盘数据的流对象
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//定义目的,将数据写入socket输出流,发给服务器
BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
//PrintWriter out = new PrintWriter(s.getOutputStream(),true);
//定义一个socket读取流,读取服务端返回的信息。
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));

String line = null;

while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufout.write(line);
bufout.newLine();
bufout.flush();
//out.println(line);
String str = bufin.readLine();

System.out.println("Server:"+str);
}
bufr.close();
s.close();
}
}
class TCPS3
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10088);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+".....connect");
//读取socket读取流中的数据
BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));
//目的,socket输出流,将大写数据写入到socket输出流,并发送给客户端。
BufferedWriter bufout = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

//PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line = null;
while ((line=bufin.readLine())!=null)
{
System.out.println(line);
bufout.write(line.toUpperCase());
bufout.newLine();
bufout.flush();
//out.println(line.toUppCase());
}
s.close();

ss.close();
}
}
代码演示四:

TCP上传文件(使用IO字符流)

把文件从客户端传到服务器端上。

容易出现的问题:没有客户端上传完后,文件结束标记,服务器无法停止连接Socket连接。


import java.io.*;
import java.net.*;
class  TCPC4
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.102",11000);

BufferedReader bufr = new BufferedReader(new FileReader("IPDemo.java"));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

String line= null;
while ((line=bufr.readLine())!=null)
{
out.println(line);
}
s.shutdownOutput();

BufferedReader bufin= new BufferedReader(new InputStreamReader(s.getInputStream()));

String str = bufin.readLine();

System.out.println(str);

bufr.close();
s.close();
}
}
class  TCPS4
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"....connect");

BufferedReader bufin = new BufferedReader(new InputStreamReader(s.getInputStream()));

PrintWriter out = new PrintWriter(new FileWriter("copy.txt"),true);

String line = null;
while ((line=bufin.readLine())!=null)
{
out.println(line);
}
PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
pw.println("上传成功!");

out.close();
s.close();
ss.close();

}
}


TCP传输的两个问题:
①客户端与服务端交互时同时阻塞,当客户端和服务端有多个阻塞方法时,如果使用缓冲区读取每行,没有刷新和换行,会导致同时阻塞;
②定义结束标记:定义结束标记的方法:定义“over“这样的字符标记,或者盖时间标记,或者使用socket的shutdownOutput和shutdownInput方法(建议使用)。
代码演示五:
需求:上传图片

客户端:

1.服务端点

2.读取客户端已有的图片数据

3.通过socket的输出流将数据发给服务端。

4.读取服务端反馈信息。

5.关闭。


import java.net.*;
import java.io.*;
class PICC
{
public static void main(String[] args) throws Exception
{
Socket s =new Socket("192.168.1.102",10090);

FileInputStream fis = new FileInputStream("L.jpg");

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 fin= s.getInputStream();

byte[] bufin = new byte[1024];

int in = fin.read(bufin);

System.out.println(new String(bufin,0,in));

fis.close();
s.close();
}
}
class PICS
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10090);

Socket s = ss.accept();

String ip = s.getInetAddress().getHostAddress();

System.out.println(ip+"....connected");

InputStream in = s.getInputStream();

FileOutputStream fout = new FileOutputStream("copy.jpg");

byte[] buf = new byte[1024];

int len= 0;
while((len=in.read(buf))!=-1)
{
fout.write(buf,0,len);
}

OutputStream out= s.getOutputStream();

out.write("上传成功".getBytes());

fout.close();
s.close();
ss.close();
}
}


TCP客户端并发访问:客户端并发访问服务器时,把服务端的处理代码封装在Runnable实现子类的run方法中,并把服务器获得的socket对象传递给该实现子类的构造函数,服务端通过while循环启动多个线程,对每个客户端请求进行并发处理,这也是一个服务器的基本原理;
import java.net.*;
import java.io.*;
class PICC1
{
public static void main(String[] args) throws Exception
{
if (args.length!=1)
{
System.out.println("请选择要上传的图片");
return ;
}
File file= new File(args[0]);
if(!(file.exists()&&file.isFile()))
{
System.out.println("图片不存在或不是图片文件");
return ;
}
if(!file.getName().endsWith(".jpg"))
{
System.out.println("图片格式错误,请选择jpg格式图片");
return ;
}
if (file.length()>1024*1024*3)
{
System.out.println("文件过大,上传失败");
return ;
}

Socket s =new Socket("192.168.1.102",10090);

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 fin= s.getInputStream();

byte[] bufin = new byte[1024];

int in = fin.read(bufin);

System.out.println(new String(bufin,0,in));

fis.close();
s.close();
}
}
/*
服务端:

这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程。
这时B客户端连接,只有等待。因为服务端还没有处理完A客户端的请求。还没有循环回来
执行下次accept方法。所以,暂时获取不到B客户端对象。那么为了可以让多个客户端
同时并发访问服务端。那么服务端最好就是将每个客户端封装到一个单独的线程中去。这
样就可以同时处理多个客户端请求。如何定义线程?只要明确了每一个客户端要在服务端
执行的代码即可。将该代码存入run方法中。
*/
class PICThread implements Runnable
{
private Socket s;
PICThread(Socket s)
{
this.s= s;
}
public void run()
{
String ip = s.getInetAddress().getHostAddress();
int c = 0;
try
{
System.out.println(ip+"...已连接");

InputStream in = s.getInputStream();

File file= new File(ip+".jpg");

while(file.exists())
file= new File(ip+"("+(c++)+")"+".jpg");
FileOutputStream fout = new FileOutputStream(file);

byte[] buf = new byte[1024];

int len= 0;

while((len=in.read(buf))!=-1)
{
fout.write(buf,0,len);
}

OutputStream out= s.getOutputStream();

out.write("上传成功".getBytes());

fout.close();
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}
class PICS1
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(10090);

while(true)
{
Socket s = ss.accept();

new Thread(new PICThread(s)).start();
}
}
}
练习:
客户端通过键盘录入用户名:

服务端对这个用户名进行校验。

如果该用户存在,在服务器端显示***,已登录。

并在客户端显示:***,欢迎光临。

如果该用户不存在,在服务器端显示 ***,尝试登陆

并在客户端显示 ***,该用户不存在。

最多就登陆三次。

import java.io.*;
import java.net.*;
class LOGINC
{
public static void main(String[] args) throws Exception
{
Socket s = new Socket("192.168.1.102",11000);

BufferedReader bfr= new BufferedReader(new InputStreamReader(System.in));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
for(int x= 0;x<3;x++)
{
String line= bfr.readLine();
if(line==null)
break;
out.println(line);

String info = in.readLine();
System.out.println("info:"+info);

if(info.contains("欢迎"))
break;
}
bfr.close();
s.close();
}
}
class LOGINT implements Runnable
{
private Socket s;
LOGINT(Socket s)
{
this.s= s;
}

public void run()
{
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip+"......已连接");
try
{
for (int x=0;x<3 ;x++ )
{
BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));

String name = in.readLine();
if (name==null)
break;

BufferedReader bufr =new BufferedReader(new FileReader("log.txt"));

PrintWriter out = new PrintWriter(s.getOutputStream(),true);

boolean flag = false;

String line=null;

while((line=bufr.readLine())!=null)
{
if(line.equals(name))
{
flag = true;
break;
}
}
if(flag)
{
System.out.println(name+"已登录");
out.println(name+"欢迎光临");
break;
}
else
{
System.out.println(name+"...尝试登陆");
out.println(name+"..用户名不存在");
}
}
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"...登陆失败");
}
}
}
class LOGINS
{
public static void main(String[] args) throws Exception
{
ServerSocket ss = new ServerSocket(11000);
while (true)
{
Socket s = ss.accept();
new Thread(new LOGINT(s)).start();
}
}
}


URL:代表一个统一资源定位符,是指向互联网资源的指针,资源可以是简单的文本或目录,也可以是更为复杂对象的引用,如对数据库或搜索引擎的查询;
常用方法:
①int getDefaultPort(): 获取与此URL关联协议的默认端口;
②String getFile(): 获取此URL的文件名;
③String getHost(): 获取此URL的主机名;
④String getPath():或取此URL的路径;
⑤int getPort(): 获取此URL的端口号;
⑥ String getProtocol(): 获取此URL的协议名称;
⑦String getQuery(): 获取此URL的查询部分;
代码演示:
import java.net.*;
class  URLDemo
{
public static void main(String[] args) throws Exception
{
//URL url=new URL("http://192.168.1.13:11000/myweb/demo.html");
URL url=new URL("http://192.168.1.13:11000/myweb/demo.html?name=haha&age=30");
System.out.println("getProtocol():"+url.getProtocol()); //http
System.out.println("getHost():"+url.getHost());//192.168.1.13
System.out.println("getDefaultPort():"+url.getDefaultPort());//80,如果关联的协议没有默认的端口,则值为-1;
System.out.println("getPort():"+url.getPort()); //  11000,如果没有设置则为-1;
System.out.println("getPath():"+url.getPath());// /myweb/demo.html
System.out.println("getFile():"+url.getFile());///myweb/demo.html?name=haha&age=30
System.out.println("getQuery():"+url.getQuery());//name=haha&age=30

/*  int port = url.getPort();
if(port==-1)
port =80;
getPort() = -1
*/
}
}
URLConnection:作用类似于socket,其实内部封装了socket,所以可以获取网络输入输出流,通过URL和URLConnection可以方便的对应用层网络数据进行读取和操作;

代码演示

import java.net.*;
import java.io.*;

class URLConnectionDemo
{
public static void main(String[] args) throws Exception
{
URL url=new URL("http://192.168.1.13:8080/myweb/demo.html");

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));

}
}


自定义图形化界面浏览器
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class  MyIEByGUI
{
private Frame f;
private TextField tf;
private Button but;
private TextArea ta;

private Dialog d;
private Label lab;
private Button okBut;

MyIEByGUI()
{
init();
}
public void init()
{
f = new Frame("My IE");
f.setBounds(300,100,500,400);
f.setLayout(new FlowLayout());

tf = new TextField(40);
but = new Button("转到");
ta = new TextArea(20,50);

d = new Dialog(f,"提示信息-self",true);
d.setBounds(400,200,240,200);
d.setLayout(new FlowLayout());

lab =new Label();
okBut=new Button("确定");

d.add(lab);
d.add(okBut);

f.add(tf);
f.add(but);
f.add(ta);

myEvent();
f.setVisible(true);

}
public void myEvent()
{
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showWebPage();

}
catch (Exception ex)
{
}

}
});
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)//用keyTyped事件不成功
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
{
try
{
showWebPage();

}
catch (Exception ex)
{
}

}
}

});
okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});

}
private void showWebPage() throws Exception
{
ta.setText("");

//http://192.168.1.13:8080/myweb/demo.html
String url =tf.getText();

int index1 = url.indexOf("//")+2;
int index2 = url.indexOf("/",index1);

String str =url.substring(index1,index2);
String[] arr = str.split(":");
String host = arr[0];
int port = Integer.parseInt(arr[1]);
String dir = url.substring(index2);
//ta.setText(url);
ta.setText(port+","+null);
//建立Socket客户端
Socket s = new Socket(host,port);
//发送请求消息头
PrintWriter out = new PrintWriter(s.getOutputStream(),true);//别忘了加true
out.println("GET "+dir+" HTTP/1.1");
out.println("Accept: */*");
out.println("Accept-Language: zh-cn");
out.println("Host: 192.168.1.13:11000");
out.println("Connection: Keep-Closed");
out.println();//记得一定要加空行
out.println();

BufferedReader bufr =
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while((line=bufr.readLine())!=null)
{
ta.append(line+"\r\n");
}
s.close();

}

public static void main(String[] args)
{
new MyIEByGUI();
}
}

private void showWebPage() throws Exception
{
//使用URL和URLConnection对showWebPage改写。
//很明显,这两个封装的应用层对象使用起来更方便简洁
ta.setText("");
String urlPath =tf.getText();
URL url=new URL(urlPath);
URLConnection conn = url.openConnection();
//System.out.println(conn);
InputStream in = conn.getInputStream();
byte [] buf =new byte[1024];
int len = in.read(buf);
ta.setText(new String(buf,0,len));
}


域名解析:用IP地址登陆网站,数字不好记忆,习惯用主机名,如www.baidu.com,从主机名到获得该主机名对应的IP地址的过程,就是域名解析,它一般是DNS服务器完成的;
域名解析步骤大致分为2步:
①查找本地的IP地址和主机名映射表,如果存在映射,则使用本机映射,如:127.0.0.1和localhost的对应关系就在这个映射表中,通过对映射文件进行配置可以实现一些功能,如:将常用网站配置在表中,这样速度快些,还可以屏蔽过滤一些垃圾网站;
②如果第一步没有找到,就会去设置的DNS服务器查找,找到对应的IP地址,获取地址后,再返回给本机IP地址,本机再通过IP地址链接上想要访问的网站。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: