黑马程序员——Java基础网络编程

时间:2023-02-26 21:57:06
------ Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

第一讲网络基础知识

一、网络模型

        1、OSI参考模型

        2、TCP/IP参考模型

黑马程序员——Java基础网络编程

        数据的发送:数据从应用层开始逐层向下封装,到达最底层,发送到指定指定主机,目标主机从模型的最底层获得数据包,在经过相逆的过程逐层拆包直应用层,获得数据。

二、网络通讯要素

1、IP地址IP地址:InetAddress

        a、网络中设备的标识

        b、不易记忆,可用主机名

        c、本地回环地址:127.0.0.1主机名:localhost

2、端口号

        a、用于标识进程的逻辑地址,不同进程的标识

        b、有效端口:0~65535,其中0~1024系统使用或保留端口。

3、传输协议

        A、UDP:无连接的传输层协议,不可靠,不考虑对方是否收到和。应用网络视频会议、聊天(如飞秋)等领域。

                特点:

                        1、将数据及源和目的封装成数据包中,不需要建立连接

                        2、每个数据报的大小在限制在64k内

                        3、因无连接,是不可靠协议

                        4、不需要建立连接,速度快

        B、TCP:是一种面向连接的、可靠的、基于字节流的传输层通信协议。。通过三次握手建立连接。如打电话、下载等。

                1、建立连接,形成传输数据的通道。

                2、在连接中进行大数据量传输。

                3、通过三次握手完成连接,是可靠协议。

                4、必须建立连接,效率会稍低。

        TCP三次握手的过程如下:

                1.客户端发送SYN(SEQ=x)报文给服务器端,进入SYN_SEND状态。

                2.服务器端收到SYN报文,回应一个SYN (SEQ=y)ACK(ACK=x+1)报文,进入SYN_RECV状态。

                3.客户端收到服务器端的SYN报文,回应一个ACK(ACK=y+1)报文,进入Established状态。

三、套接字(Socket)

        1.套接字(Socket)就是为网络服务提供的一种机制。

        2.通信的两端都有套接字(Socket)。

        3.网络通信其实就是套接字(Socket)间的通信。

        4.数据在两个套接字(Socket)间通过IO传输。

四、获取指定主机的IP

示例一:
import java.net.InetAddress;
import java.net.UnknownHostException;

public class IpDemo {
public static void main(String[] args) throws UnknownHostException
{
//获取本机InetAddress对象,获取不成功抛UnknownHostException
InetAddress i=InetAddress.getLocalHost();
//本地主机的名字和IP地址或者分别获取
System.out.println(i.toString());
System.out.println("address i:"+i.getHostAddress());
System.out.println("name i:"+i.getHostName());

//获取域名为www.sina.com的InetAddress对象
InetAddress ia=InetAddress.getByName("www.sina.com");
//此方法需要域名解析
System.out.println("address ia:"+ia.getHostAddress());
System.out.println("name ia:"+ia.getHostName());

//百度有多台主机提供服务,用此方法获取全部主机
InetAddress[] baidu=InetAddress.getAllByName("www.baidu.com");
for (InetAddress b :baidu)
{
String ip=b.getHostAddress();
String name=b.getHostName();
System.out.println("百度主机IP="+ip+"\t百度主机名字="+name);
}
}
}

第二讲UDP(用户数据报协议User Datagram Protocol )

一、UDP传输思路:

        1.DatagramSocket建立服务与DatagramPacket构建数据包。

        2.建立发送端,接收端。

        3.建立数据包。

        4.调用Socket的发送、接收方法。l

        5.关闭Socket。

发送端与接收端是两个独立的运行程序。

二、UDP客户端、服务端的建立的具体步骤:

客户端:

1.建立udpsocket服务。

        DatagramSocket udps=new DatagramSocket(8189);

        8189是客服端指定数据从本机发送的端口,不写就由系统随机分配端口发送数据。

2.提供数据,并将数据封装到数据包中。用于发送数据:

        byte[] buf="udp ge men lai le ".getBytes();

        DatagramPacket dp= new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.100"),3000);

        数据如果是字符串,则将字符串转换成字节数组,并指定远程主机的IP:192.168.1.100端口3000上。

3.通过socket服务的发送功能,将数据包发出去。

        ds.send(dp);

4.关闭资源。

        ds.close();

服务端:

1.定义udpsocket服务。通常会监听一个端口。

        DatagramSocket ds= new DatagramSocket(3000);

        其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来该应用程序可以处理。监听的端口必须与客户端的发送到此主机的端口一致。

2.定义一个数据包,因为要存储接收到的字节数据。

        byte[] buf=new byte[1024];

        DatagramPacket dp=new DatagramPacket(buf,buf.length);

        数据包对象中有更多功能可以提取字节数据中的不同数据信息。

3.通过DatagramSocket服务的receive方法将接收到的数据存入已定义好的数据包中。

        ds.receive(dp);

        通过数据包对象的特有功能,将这些不同的数据取出。打印在控制台上。

        String ip=dp.getAddress().getHostAddress();

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

        int port=dp.getPort();//获取端口

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

4.关闭资源。

        ds.close();

示例二:

/*UDP聊天程序:
需求:用多线程编写一个聊天程序。实现自己跟自己聊天。

建立UDP客户端步骤:
1.建立udpsocket服务。
2.提供数据,并将数据封装到数据包中。
3.通过socket服务的发送功能,将数据包发出去。
4.关闭资源。
建立UDP服务端步骤:
1.建立udpsocket服务。通常会监听一个端口。
2.构建一个数据包,因为要存储接收到的字节数据。
因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
3.通过socket服务的receive方法将接收到的数据存入已定义好的数据包中。
4.通过数据包对象的特有功能,将这些不同的数据取出。打印在控制台上。
5.关闭资源。
*/
/*------------------------UDP聊天程序发送端-----------------*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
class UdpSend implements Runnable
{
private DatagramSocket ds;
public UdpSend(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
try
{
//2.建立带缓存的键盘录入对象
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=bufr.readLine())!=null)
{
if("886".equals(line))
break;
//3.构建数据包,封装数据。
byte[] buf=line.getBytes();
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),20000);
//4.发送数据包。
ds.send(dp);
}
}
catch (Exception e)
{
throw new RuntimeException("发送端失败");
}
}
}

class UdpRece implements Runnable
{
private DatagramSocket ds;
public UdpRece(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
try
{
while(true)
{
//2.构建数据包,用于存储数据
byte[] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//3.将获取到的数据,存储到dp对象中
ds.receive(dp);
//4.通过dp对象中的getDate()方法将数据读取出来,并打印
int port=dp.getPort();
String ip=dp.getAddress().getHostAddress();
String data=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+": "+data+".......port:"+port);
}
}
catch (Exception e)
{
throw new RuntimeException("接收端失败");
}
}
}

public class UdpChatDemo
{
public static void main(String[] args) throws Exception
{
//1.建立udpSocket服务, 端口1025用于发送数据,端口20000用于接收数据
DatagramSocket sendSocket=new DatagramSocket(1025);
DatagramSocket receSocket=new DatagramSocket(20000);
//开启线程
new Thread(new UdpSend(sendSocket)).start();
new Thread(new UdpRece(receSocket)).start();

}
}

第三讲TCP(传输控制协议Transmission Control Protocol/Internet Protocol)

一、TCP传输思路:

        1.Socket用于客户端和ServerSocket用于服务端。

        2.建立客户端和服务器端。

        3.建立连接后,通过Socket中的IO流进行数据的传输。

        4.关闭socket。

        同样,客户端与服务器端是两个独立的应用程序。

二、TCP客户端、服务端建立步骤:

客户端:

1.建立Socket服务,指定远程主机IP和端口。如果连接失败,会出现异常。

        Socket s=new Socket("127.0.0.1",3999);

2.拿到Socket发送数据的流对象,并发送数据

        OutputStream out=s.getOutputStream();

        out.write("服务端 你好".getBytes());

3.获取Socket接收数据的流对象,用于接收数据。

        InputStream in=s.getInputStream();

        byte[] buf=new byte[1024];

        阻塞式方法read读取数据。并打印。

        int len =in.read(buf);

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

4.关闭资源。

        s.close();

        通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。因为TCP是面向连接的。所以在建立socket服务时,就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。否则直接抛异常。

服务端:

1.建立服务端的socket服务,并监听端口3999。

        ServerSocket  ss=new ServerSocket(3999);

2.通过accept方法(阻塞式方法)获取连接过来的客户端对象。

        Socket s=ss.accept();

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

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

3.获取客户端发送过来的数据,那么要使用客户端对象的输入流read方法来读取数据。

        InputStream in=s.getInputStream();

        byte[] buf=new byte[1024];

        int len=in.read(buf);

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

4.得到Socket用于发数据的输出流,通过输出流中的write方法发送数据。

        OutputStream out=s.getOutputStream();

        out.write("哥们收到  你也好!".getBytes());

5.关闭资源。

        ss.close();

三、Socket()和connect(SocketAddress endpoint)

TCP还可以通过不带参数的Socket通过步骤1、2建立连接:

        1、Socket() 通过系统默认类型的 SocketImpl 创建未连接套接字。

        2、void connect(SocketAddress endpoint) 将此套接字连接到服务器。

        SocketAddress是一个抽象类,它的子类InetSocketAddress实现了IP套接字地址(IP地址+端口号)。

对于服务端还可以用ServerSocket(int port,int backlog)方法限定队列的最大长度,即最多允许客户端连接的数量(backlog)。

示例三:

/*TCP上传文本数据
需求:向服务器上传一个文本文件,上传完毕,服务器返回上传成功。
客户端与服务端独立运行,为了方便阅读放在同一个程序中。
分析:
要向服务器发送文本文件,需要读取文件,通过Socket输出流发送数据,当文本读取结束后
一定要给服务器发送一个结束标记,可以自定义,最好用Socket自带的结束标记,否则,服务器会
一直等待。服务端收到结束标记后,发送“上传成功”数据给客户端。
步骤:
1.建立客户端Socket服务。
2.建立带缓存的文件读取流对象,用来读取文件数据。
3.通过Socket中的输出流发送数据,发送完必须加结束标记。
4.等待读取服务器返回的数据并打印出来。
5.关闭资源。
*/
import java.io.*;
import java.net.*;
class TextClient
{
public static void main(String[] args)
{
try {
//1.建立socket服务,并指定数据由端口3927发送。
Socket s=new Socket("127.0.0.1",3927);//该句单独处理为好
//2.建立一个带缓存的读取文件流对象,用于读取数据。
BufferedReader bufr=new BufferedReader(new FileReader("c:\\pppp.java"));
//3.建立一个带缓存的Socket输出流对象。用于发送数据。
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

String line=null;
while((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
//文本发送完毕,加上结束标记。
s.shutdownOutput();
//4.等待接收服务端返回的数据。
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
String str=bufIn.readLine();
System.out.println(str);

//5.关闭资源。
bufr.close();
s.close();
}
catch(Exception e)
{
throw new RuntimeException("数据上传失败");
}
}
}
//-----------------------服务端---------------------
class TextServer
{
public static void main(String[] args)
{
try
{
//1.建立ServerSocket服务,并监听3927端口。
ServerSocket ss=new ServerSocket(3927);
//2.获取客户端对象。
Socket s=ss.accept();
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
//3.定义一个带缓冲的读取流对象,读取客户端发送来的数据。
BufferedReader bufr=
new BufferedReader(new InputStreamReader(s.getInputStream()));
//4.定义一个输出流对象,将读取到的数据写入文本中。
//BufferedWriter bufw=new BufferedWriter(new FileWriter("server.txt",true));
PrintWriter pw=new PrintWriter(new FileWriter("c:\\server.txt"),true);
String line=null;
while((line=bufr.readLine())!=null)
{
//bufw.write(line);
//bufw.newLine();
//bufw.flush();
pw.println(line);
}
//5.发送“上传成功”给客户端。
BufferedWriter bufout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bufout.write("上传成功");
bufout.newLine();
bufout.flush();

//6.关闭资源。
s.close();
//bufw.close();
pw.close();
}
catch(Exception e)
{
throw new RuntimeException("服务端:上传失败 ");
}
}
}
示例四:

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/*-----------------Tcp文本转换练习----------------------------------
需求:建立一个文本转换服务器。
客户端给服务端发送文本,服务端将文本转成大写在返回给客户端。
而且客户端可以不断的进行文本转换。当客户端输入over时,转换结束。
两个类独立运行。
分析:
客户端:既然是操作设备上的数据,那么就可以使用IO技术,并按照IO的操作规律来思考。
源:键盘录入。
目的:网络设备,网络输出流。
而且操作的是文本数据。可以选择字符流。

步骤:
1.建立服务。
2.获取键盘录入。
3.将数据发送给服务端。
4.获取服务端返回的大写数据
5.结束,关闭资源

都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。
*/
//---------------------------客户端---------------------------------
class TransClient
{
public static void main(String[] args)
{
try
{
//1.建立Socket服务,指定数据从3924端口发出。
Socket s=new Socket("127.0.0.1",3924);

//2.定义读取键盘数据的流对象。
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));

//3.定义目的,将数据写入到socket输出流,发给服务端。
//BufferedWriter bufout=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
PrintWriter out=new PrintWriter(s.getOutputStream(),true);

//4.定义一个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对象后面加上了true,此句就带刷新功能。发送数据
out.println(line);
//读取服务端返回过来的数据
String str=bufin.readLine();
System.out.println("server:"+str);
}
//5.关闭资源。
bufr.close();
s.close();
}
catch (Exception e)
{
System.out.println("客服端失败");
}

}
}
/*
服务端:
源:socket读取流
目的:socket输出流。
都是文本,装饰。
*/
//--------------------------服务端-----------------------------
class TransServer
{
public static void main(String[] args)
{
try
{
//1.建立ServerSocket服务端服务,并监听端口3924.
ServerSocket ss=new ServerSocket(3924);

//2.通过accept方法,获取客户端对象
Socket s=ss.accept();

//3.读取socket读取流中的数据
BufferedReader bufIn=new BufferedReader(new InputStreamReader(s.getInputStream()));

//4.通过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)
{
//bufOut.write(line.toUpperCase());
//bufOut.newLine();
//bufOut.flush();
out.println(line.toUpperCase());
}
//5.关闭资源。
s.close();
ss.close();
}
catch(Exception e)
{
System.out.println("服务端failed");
}
}
}
/*
该列子出现的问题:客户端和服务端都在莫名的等待,为什么呢?
因为客户端和服务端都有阻塞式方法。这些方法没有读到结束标记。那么就一直等
而导致两端,都在等待。
*/
示例五:

/*Tcp并发上传图片
需求:支持多个客户端同时上传图片
分析:支持多个客户端同时上传图片,服务端开启多线程,accept方法每接收一个
客户端对象就开启一个线程,上传图片需要字节流FileInputStream关联上传图片
(read方法读取数据),服务端需要FileOutputStream关联存储图片。通过Socket
的OutputStream的输出流对象发送数据。
客户端步骤:
1.将图片路径通过主函数传值给虚拟机。
2.只上路径合法、png格式、大小不超过8M的文件。
3.建立Socket服务。
4.关联文件,读取数据。通过Socket输出流对象发送数据。
文件发送完毕,发送结束标记。
5.等待服务器返回的信息。
6.关闭资源。
* */
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/*--------------------客户端-----------------------------*/
class PicClient
{
public static void main(String[] args) throws Exception
{
//1.主函数传入一个图片所在路径。
if(args.length!=1)
{
System.out.println("请选择一个png格式的图片");
return ;
}
//2.判断文件是否存在,是否是文件。
File file=new File(args[0]);
if(!(file.exists() && file.isFile()))
{
System.out.println("该文件有问题,要么不存在,要么不是文件");
return;
}
//文件格式为png
if(!file.getName().endsWith(".png"))
{
System.out.println("图片格式错误,请重新选择");
return;
}
//文件大小不大于8M
if(file.length()>1024*1024*8)
{
System.out.println("文件过大");
return ;
}

//3.建立Socket服务,指定信息从1234端口发出。
Socket s=new Socket("127.0.0.1",1234);

//4.关联数据文件,通过Socket输出流发送数据。
FileInputStream fi=new FileInputStream(file);
OutputStream out=s.getOutputStream();
byte[] buf=new byte[1024];
int num=0;
while((num=fi.read(buf))!=-1)
{
out.write(buf,0,num);
}
//告诉服务端数据已经写完。
s.shutdownOutput();

//5.通过Socket输入流read方法,等待读取服务端返回的数据。
InputStream in=s.getInputStream();
byte[] bufIn=new byte[1024];
int len=0;
len=in.read(bufIn);
System.out.println(new String(bufIn,0,len));

//6.关闭资源。
s.close();
fi.close();
}
}
/*-------------------------------服务端----------------------------------
服务端:
步骤:
1.建立ServerSocket服务,
每接收一个客户端对象就开启一个线程。
2.确定存储文件名字、路径。关联写入文件。
3.通过Socket输入流对象,read方法读取数据,
FileOutputStream的对象写入数据。
4.文件存储完毕,给客户端发送“上传成功”信息。
5.关闭资源。
*/
class PicThread implements Runnable
{
private Socket s;
PicThread(Socket s)
{
this.s=s;
}
public void run()
{
//获取对方ip
String ip=s.getInetAddress().getHostAddress();
try
{
//确定文件存储名字
int count=1;
System.out.println(ip+".....connected");
File file=new File(ip+"("+count+")"+".png");
while(file.exists())
{
file=new File(ip+"("+(count++)+")"+".png");
}
//3.关联写入文件,通过Socket输入流对象中的read方法读取数据。
InputStream in=s.getInputStream();
FileOutputStream fos=new FileOutputStream(file);
byte[] buf=new byte[1024];
int leng=0;
while((leng=in.read(buf))!=-1)
{
fos.write(buf, 0, leng);
}
//4.文件读取、存储完毕,返回客户端信息。
OutputStream out=s.getOutputStream();
out.write("上传成功".getBytes());

//5.关闭资源。
fos.close();
s.close();

}
catch (Exception e)
{
throw new RuntimeException(ip+"上传失败");
}
}
}

public class PicServer
{
public static void main(String[] args) throws Exception
{
//1.建立ServerSocket服务,并监听1234.
ServerSocket ss=new ServerSocket(1234);

//2.每接收一个客户端对象,就开启一个线程。
while(true)
{
Socket s=ss.accept();
new Thread(new PicThread(s)).start();
}
}
}
示例六:

/*TCP客户端并发登陆
需求:
1.客户端键盘录入用户名,服务端从指定文本文件校验该用户名。
如果存在,向客户端发送发送:***,欢迎光临。
如果不存在,向客户端发送发送:***,该用户名不存在。
2.一次连接最多允许3次登陆。超过就断开连接。
* */
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
//----------------------客户端------------------------
class LoginClient
{
public static void main(String[] args) throws Exception
{
//1.建立Socket服务,发送数据到该IP的1026端口。
Socket s= new Socket("127.0.0.1",1026);

//2.创建带缓存的键盘输入流对象,读取键盘数据。
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
//3.创建数据发送流对象。
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
//4.创建数据接收字符流对象。
BufferedReader bufw=new BufferedReader(new InputStreamReader(s.getInputStream()));

//最多3次登陆
for(int x=0; x<3;x++)
{
//读取键盘数据
String line=bufr.readLine();
if(line==null)
break;
//5.发送用户名给服务端。
out.println(line);
//6.等待校验返回的信息。
String info=bufw.readLine();
System.out.println("info: "+info);
//校验成功结束程序。
if(info.contains("欢迎"))
break;
}
//7.关闭资源。
s.close();
bufr.close();
}
}
class UserThread implements Runnable
{
private Socket s;
UserThread(Socket s)
{
this.s=s;
}
public void run()
{
//获取客户端ip地址,并显示连接
String ip= s.getInetAddress().getHostAddress();
System.out.println(ip+".....connected");
try
{
//最多三次校验客户端用户名
for (int i = 0; i < 3; i++)
{
//3.建立带缓存的Socket输入流对象,用于读取客户端发送过来的信息。
BufferedReader bufIn=
new BufferedReader(new InputStreamReader(s.getInputStream()));
String name=bufIn.readLine();
//4.关联用户名数据库txt。用于校验用户名。
BufferedReader bufr=new BufferedReader(new FileReader("TCP.txt"));
//5.建立Socket输出流,用于发送信息给客户端。
PrintWriter out=new PrintWriter(s.getOutputStream(),true);

//6.校验用户名
String line=null;
Boolean flag=false;
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+",该用户名不存在");
}
}
//7.关闭资源。
s.close();
}
catch (Exception e)
{
throw new RuntimeException(ip+"校验失败");
}
}
}
//----------------------服务端----------------------
public class LoginServer
{
public static void main(String[] args) throws Exception
{
//1.建立ServerSocket服务,并监听1026端口。
ServerSocket ss=new ServerSocket(1026);
//2.每接收一个客户端对象就开启一个线程。
while(true)
{
Socket s=ss.accept();
new Thread(new UserThread(s)).start();
}
}
}

四、客户端和服务的浏览器演示

        浏览器是一个标准的客户端,它可以对服务端传送过来的数据消息进行解析,把符合应用层协议的消息部分解析后,将头信息拆包掉,传送到应用层,只保留了正确的正文主题部分显示在主体部分上。

        而由于使用java编译是在传输层和网际层处理的,所以,会接受到全部的消息,包含了头消息。而浏览器处于应用层,已将发送来的头消息去除,只留下了主体信息。

示例七:

/*
1.浏览器客户端-自定义服务端
客户端:浏览器(telnet) 127.0.0.1:8888
服务端:自定义 监听端口8888。

2.浏览器-Tomcat
客户端:浏览器。 127.0.0.1:8080
服务端:Tomcat服务器。

3.自定义浏览器-tomcat服务器
* */
//-------------------------1.浏览器客户端-自定义服务端-------------------------
import java.io.*;
import java.net.*;
public class ServerDemo
{
public static void main(String[] args)throws Exception
{
//1.创建服务,监听端口
ServerSocket ss=new ServerSocket(8888);

//2.获取客户端对象
Socket s=ss.accept();
//获取客户端ip
String ip=s.getInetAddress().getHostAddress();
System.out.println(ip);

//3.读取客户端流数据
InputStream in=s.getInputStream();
byte[] buf=new byte[1024];
int len=in.read(buf,0,255);
System.out.println(new String(buf,0,len));

//4.返回信息写入客户端输出流
PrintWriter out=new PrintWriter(s.getOutputStream(),true);
out.println("<font color='red' size='7'>客户端你好!</font>");

//5.关闭资源。
s.close();
ss.close();
}
}
/*浏览器请求消息头:
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, *//* 此处只有一个/,避免与注释冲突
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0) LBBROWSER
Accept-Encoding: gzip, deflate
Host: 127.0.0.1:8888
Connection: Keep-Alive
*/
//---------------------------3.自定义浏览器-tomcat服务器--------------------
public class MyIE
{
public static void main(String[] args) throws Exception
{
//1.创建Socket服务,确定数据发送到的IP地址和对方端口
Socket s=new Socket("127.0.0.1",8080);

//2.创建Socket输出流对象。
PrintWriter out= new PrintWriter(s.getOutputStream(),true);
//3.模拟浏览器发送请求消息头。
out.println("GET /myweb/demo.html HTTP/1.1");
out.println("Accept:*/*");
out.println("Accept-Language: zh-CN");
out.println("Host: 127.0.0.1:8080");
out.println("Connection: Keep-Alive");
//发送一个空行,表示和请求头分开
out.println();

//4.获取服务器数据
BufferedReader bufr=
new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=bufr.readLine())!=null)
{
System.out.println(line);
}
//5.关闭资源。
s.close();
}
}
/*tomcat服务器应答消息头:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"150-1422201489934"
Last-Modified: Sun, 25 Jan 2015 15:58:09 GMT
Content-Type: text/html
Content-Length: 150
Date: Wed, 28 Jan 2015 13:52:38 GMT

<html>

<body>
<hl>这是我的主页</hl>
<font size=5 color=red>欢迎光临</font>
<div>
这是我的第一个html</br>
</div>
</body>
</html>
*/

四、URL和URLConnection

        1、URL:统一资源定位符是对可以从互联网上得到的资源的位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

        2、URI:统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串。 该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互操作。URI由包括确定语法和相关协议的方案所定义。URI的范围要比URL大。

        3、URLConnection:抽象类URLConnection(子类HttpURLConnection、JarURLConnection)是所有类的超类,它代表应用程序和URL之间的通信链接。此类的实例可用于读取和写入URL引用的资源。通常,创建一个到URL的连接需要几个步骤:

        1、通过在URL上调用openConnection方法创建连接对象。

        2、处理设置参数和一般请求属性。

        3、使用connect方法建立到远程对象的实际连接。

        4、远程对象变为可用。远程对象的头字段和内容变为可访问。

以前Socket在传输层,然而URLConnection让开发者处于应用层,用此方法获取的web信息没有响应头。

示例八:

/*URL URLConnection
*/
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class URLDemo
{
public static void main(String[] args) throws Exception
{
URL url=new URL("http://www.baidu.com");//throws MalformedURLException

System.out.println("url.getFile(): "+url.getFile());//获取此 URL 的文件名。
System.out.println("url.getHost(): "+url.getHost());//获取此 URL 的主机名(如果适用)。
System.out.println("url.getPath(): "+url.getPath());//获取此 URL 的路径部分。
System.out.println("url.getFile(): "+url.getFile());// 获取此 URL 的文件名。
System.out.println("url.getPort(): "+url.getPort());//获取此 URL 的端口号。
<span style="white-space:pre"></span>System.out.println("url.getProtocol(): "+url.getProtocol() );//获取此 URL 的协议名称。
<span style="white-space:pre"></span>System.out.println("url.getQuery(): "+url.getQuery());//获取此 URL 的查询部分。

<span style="white-space:pre"></span>//返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。带协议 就在应用层了 就不用写socket
<span style="white-space:pre"></span>URLConnection conn=url.openConnection();
<span style="white-space:pre"></span>System.out.println(conn);

<span style="white-space:pre"></span>InputStream in=conn.getInputStream();
<span style="white-space:pre"></span>byte[] buf=new byte[1024];
<span style="white-space:pre"></span>int len=in.read(buf);
<span style="white-space:pre"></span>System.out.println(new String(buf,0,len));

<span style="white-space:pre"></span>// InputStream openStream() 就等于 openConnection().getInputStream()
<span style="white-space:pre"></span>//打开到此 URL 的连接并返回一个用于从该连接读入的 InputStream。

<span style="white-space:pre"></span>//在URLConnection中
<span style="white-space:pre"></span>// String getContentType() 返回 content-type 头字段的值。
<span style="white-space:pre"></span>System.out.println(conn.getContentType());//Content-Type:text/html

}
}
示例九:

/*GUI界面访问tomcat
需求:开发一个GUI界面,输入要访问的地址http://127.0.0.1:8080/myweb/demo.html
获取自定义的网页demo.html的数据。
*/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 window");
f.setBounds(300,100,600,500);
f.setLayout(new FlowLayout());

tf = new TextField(60);
but = new Button("转到");
ta = new TextArea(25,70);

d = new Dialog(f,"提示信息-self",true);
d.setBounds(400,200,240,150);
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);
}
//实现事件
private void myEvent()
{

okBut.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
d.setVisible(false);
}
});
d.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
d.setVisible(false);
}
});
//实现键盘回车结束录入事件
tf.addKeyListener(new KeyAdapter()
{
public void keyPressed(KeyEvent e)
{
try
{
if(e.getKeyCode()==KeyEvent.VK_ENTER)
showDir();
}
catch (Exception ex)
{

}
}
});

//实现跳转结束录入事件。
but.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
try
{
showDir();
}
catch (Exception ex)
{

}
}
});
//窗口关闭功能。
f.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
}
//发送请求,获取服务器数据
private void showDir()throws Exception
{
/*第一种方式:
//http://127.0.0.1:8080/myweb/demo.html
//清除文本窗体数据。
ta.setText("");
//获取键盘输入的数据。
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 path = url.substring(index2);
//ta.setText(str+"...."+path);

//建立服务 发送请求头。
Socket s = new Socket(host,port);
PrintWriter out = new PrintWriter(s.getOutputStream(),true);

out.println("GET "+path+" HTTP/1.1");
out.println("Accept: /*");
out.println("Accept-Language: zh-cn");
out.println("Host: 192.168.1.254:8080");
out.println("Connection: closed");

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();
*/
//第二种方式URLConnection处理后返回的信息就没有消息头了。
ta.setText("");
//获取输入的路径
String path=tf.getText();
try
{
//封装地址对象
URL url =new URL(path);
//连接网页服务器
URLConnection conn=url.openConnection();
//读取流,用于读取服务器返回数据
InputStream in=conn.getInputStream();

byte[] buf=new byte[1024];

int len=in.read(buf);
//将数据显示在文本区中
ta.setText(new String(buf,0,len));
}
catch (Exception e)
{
throw new RuntimeException("连接"+path+"网站失败");
}
}

public static void main(String[] args)
{
new MyIEByGUI();
}
}
/*第一种方式tomcat服务区返回的数据。分为消息头和数据体
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"150-1422201489934"
Last-Modified: Sun, 25 Jan 2015 15:58:09 GMT
Content-Type: text/html
Content-Length: 150
Date: Wed, 28 Jan 2015 15:07:43 GMT
Connection: close

<html>

<body>
<hl>这是我的主页</hl>
<font size=5 color=red>欢迎光临</font>
<div>
这是我的第一个html</br>
</div>
</body>
</html>
*/

五、域名解析

        域名解析:就是把人们容易记住的网站名字(域名,如www.baidu.com),先通过本地DNS查找,未找到再通过最近的DNS(外部)查到对应域名主机的IP地址(百度的其中一个主机IP 61.135.169.125),这样浏览器就以访问IP的形式,访问百度网站了。

        Xp系统的本地DNS配置文件路径 C:\Windows\Systems\drivers\ext\host

        win7系统的本地DNS配置文件路径 C:\Windows\System32\drivers\etc