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

时间:2023-02-26 22:11:31
------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------


网络编程

一、概述。

        当我们需要在计算机和计算机之间进行数据传输的时候,我们就需要通过网络通讯。那么我们应该怎么获取网络通信,网络通信有何种要素和模型?

        首先,我们要从一台计算机中将数据传输到另一台计算机中,我们就要找到目标主机,如何找到数据目的(主机),那么这台主机就需要一个表示——IP地址,就相当于这台主机的名字。IP地址有四段,每一段都是1个字节,最大可以表示成255.255.255.255,现在由于IP地址的分配紧张又出现了六段地址的IPV6地址,以此来扩大IP地址范围。由于IP地址字段不是很好记,也可以给IP地址对应一个容易阅读的名称来表示,这个叫做主机名。

        其次,当我们的数据到达目的主机之后,我们需要把数据发送到目的主机指定的软件上,为了表示这些应用程序,所以给这些网络应用程序都用数字来标识,为了方便称呼这个数字,我们把它叫做端口,逻辑端口。端口范围为0-65535。TomCat服务器默认端口8080,Mysql服务器默认端口3306,web服务端口80。

        所以我们在进行网络通讯的时候需要先找IP在找端口,一个应用程序可以对应多个端口,但是一个端口只能对应一个应用程序。

        再次,计算机在通信过程中也需要定义一个通信规则,两方都以同样的规则发送和接受数据,这个规则叫做协议。国际组织定义一个通用的协议Tcp/Ip协议。

二、通讯要素和网络参考模型。

        网络在传输过程中,为了更细致的划分其每次传输层次所对应的功能不一样,我们将网络分成了下面几层:

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

        在TCP/IP参考模型中,应用层对应了HTTP和FTP协议,传输层对应TCP和UDP协议,网络层对应IP协议。

        在数据传输过程中,在源主机中从上到下的对数据进行封装然后传输到目的主机在从下到上的对数据进行解读封装,最终就留下了原始的数据。

        我们在用java语言来进行网络通信时,我们需要对象来操作三个要素:IP地址,端口,协议

        IP对象:InetAddress类,它有两个子类:Inet4Address和Inet6Address,分别代表IPV4和IPV6。它将构造函数私有化了,所以提供了静态的方法来获取本类对象:getLocalHost()获取本机IP地址InetAddress对象。

        该对象还有以下这些方法:

package com.itheima;
import java.net.*;
public class IPDemo 
{
public static void main(String[] args) throws UnknownHostException
{
InetAddress ia=InetAddress.getLocalHost();//若获取本地IP失败贼抛出异常
String address = ia.getHostAddress();//获取该对象的IP地址,以字符串的形式
String hostname=ia.getHostName();//获取该IP地址代表主机的主机名
System.out.println("这台主机的IP地址是:"+address+"这台主机名称叫做:"+hostname);
InetAddress ia2=InetAddress.getByName("www.baidu.com");//通过主机名或者字符串IP地址获取该主机的IP地址InetAddress对象
InetAddress[] ia3 = InetAddress.getAllByName("www.baidu.com") ;//百度主机不止一个IP地址,可以通过这个方法获取所有的IP地址对象
for(InetAddress i:ia3)
{
System.out.println("这台主机的IP地址是:"+i.getHostAddress()+"这台主机名称叫做:"+i.getHostName());
}
System.out.println("这台主机的IP地址是:"+ia2.getHostAddress()+"这台主机名称叫做:"+ia2.getHostName());
}
}
        注意, getByName()方法内主要传入字符串IP地址最好,传入主机名需要DNS服务器来解析。

        端口:就是一应用程序的表示,所以没有对象封装。

        传输协议:TCP和UDP协议。

        UDP:它是面向无连接的,用UDP协议传输,在源主机中将数据打成数据包,然后发送出去,至于传输是否成功是不管的,如果传输不成功则放弃这个包,它每一个数据包大小限制在64k以内,它是不可靠协议,但是由于不需要连击所以发送速度非常快。类似于在我们现实生活中的发送快递,聊天软件,视频会议。

        TCP:它是面向连接的协议,建立了数据的传输通道,在连接中进行大量的数据传输,通过三次握手完成连接,是可靠协议,所以传输效率会很低。类似于下载,精确的数据获取方式。

三、socket

        所谓socket就是为网络服务提供的一种机制,其通信两端都有Socket端口,而网络通信就是Socket之间的通信,数据就在Socket之间通过IO传输。类似于港口,两个港口之间通过船通信。

四、UDP协议

       每一个协议都有其自己的Socket服务,如何建立UDP的Socket服务?DatagramSocket类就是建立UDP协议的Socket服务,它通过调用该类对象的send和receive()方法来收发数据,由于UDP协议是将数据打成一个数据包来发送,所以有定义了一个DatagramPacket对象来封装数据包。对发送端来说,将数据封装成数据包,对接受端来说,将数据包接受,然后解开封装。        发送端建立步骤如下:
package Udp;
import java.net.*;
public class UDPSend
{
public static void main(String[] args) throws SocketException, Exception//发送端
{
InetAddress i=InetAddress.getLocalHost();
//1、建立DatagramSocket端点,传入端口号
DatagramSocket ds=new DatagramSocket();//建立socket失败会抛出异常
byte[] arr="我们来了,UDP!".getBytes();//每个包最大是64k
//2、将需要发送的数据打包,格式如下(数据,数据长度,InetAddress,端口)注意数据是一个字节数组
DatagramPacket p = new DatagramPacket(arr,arr.length,i,8086);
//3、发送数据,不建立连接
ds.send(p);
//4、关闭资源
ds.close();
}
}
        接收端建立步骤如下:
package Udp;
import java.io.*;
import java.net.*;
public class UDPReceive //接收端
{
public static void main(String[] args) throws Exception
{
//1、建立接受端DatagramSocket,注意端口要和发送端数据包的端口相同
DatagramSocket da = new DatagramSocket(8086);
while(true)
{
byte[] arr =new byte[1024*64];
//2、建立一个数据包对象用于接受发送过来的数据包
DatagramPacket dp=new DatagramPacket(arr,arr.length);
//3、接受数据包存入dp中
da.receive(dp);//这时一个阻塞式方法,没有接受到数据也会等待
//4、对数据包解封装
System.out.println("发送端主机IP为:"+dp.getAddress().getHostAddress()+"主机名称为:"+dp.getAddress().getHostName());
System.out.println("接收到的数据是:"+new String(dp.getData(),0,dp.getLength()));
System.out.println("发送端端口号是:"+dp.getPort());
}
//5、关闭接收端DatagramSocket
//da.close();由于上面的无限循环所以不能执行这句话
}
}
        在发送端加上键盘输入技术则有:
package Udp;
import java.io.*;
import java.net.*;
public class UDPChat
{
public static void main(String[] args) throws Exception
{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
DatagramSocket ds=new DatagramSocket();
byte[] arr=new byte[1024*64];
String s=null;
while((s=br.readLine())!=null)//阻塞式方法,若没有读取的数据就会线程等待
{
if("over".equals(s))
break;
arr=s.getBytes();//按照指定格式编码
DatagramPacket dp=new DatagramPacket(arr,arr.length,InetAddress.getLocalHost(),8086);
ds.send(dp);
}
ds.close();
br.close();
}
}
        在两台主机上各自建立一个发送端和一个接收端我们就可以实现UDP的聊天软件。注意:接受端和发送端是同时运行的,所以需要用到多线程技术。
package Udp;
import java.io.*;
import java.net.*;
public class UDPChat
{
public static void main(String[] args) throws Exception
{
DatagramSocket sends=new DatagramSocket();
DatagramSocket receives=new DatagramSocket(8087);
Sender s=new Sender(sends);
Receiver r = new Receiver(receives);
Thread t1=new Thread(s);
Thread t2=new Thread(r);
t1.start();
t2.start();
}
}
class Sender implements Runnable
{
DatagramSocket ds;
Sender(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
BufferedReader br = null;
byte[] arr=new byte[1024*64];
String s=null;
try {
br=new BufferedReader(new InputStreamReader(System.in));
while((s=br.readLine())!=null)
{
if("over".equals(s))
break;
arr=s.getBytes();//按照指定格式编码
DatagramPacket dp=new DatagramPacket(arr,arr.length,InetAddress.getLocalHost(),8087);
ds.send(dp);
}
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
finally
{
try
{
ds.close();
if(br!=null)
br.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}

}
}
class Receiver implements Runnable
{
DatagramSocket ds;
Receiver(DatagramSocket ds)
{
this.ds=ds;
}
public void run()
{
while(true)
{
byte[] arr =new byte[1024*64];
DatagramPacket dp=new DatagramPacket(arr,arr.length);
try
{
ds.receive(dp);
}
catch (IOException e)
{
e.printStackTrace();
}
System.out.println("发送端主机IP为:"+dp.getAddress().getHostAddress()+"主机名称为:"+dp.getAddress().getHostName());
System.out.println("接收到的数据是:"+new String(dp.getData(),0,dp.getLength()));
System.out.println("发送端端口号是:"+dp.getPort());
}
}
}

五、Tcp协议

        对Tcp协议来说,它也有自己的Socket。Tcp分为客户端和服务端,客户端对应的对象是socket类对象,而服务端对应的对象是ServerSocket类对象。
        客户端:         通过查阅Socket类对象,在对象建立之后就会去连接主机。这是因为Tcp是面向连接的,所以在建立Socket服务时必须要有服务器的存在,并且要连接成功,形成通路后在该通路上进行数据传输。         创建客户端:     
package Udp;
import java.io.*;
import java.net.*;
public class TcpClient
{
public static void main(String[] args) throws Exception, IOException
{
//1、建立客户端Socket,确定服务器的IP地址和端口
Socket s=new Socket(InetAddress.getByName("www.baidu.com"),443);
//2、为了发送数据,我需要获取Socket中的输出流
OutputStream os=s.getOutputStream();
os.write("百度你好".getBytes());
//3、客户端接收数据,需要获取Socket中的输入流
InputStream is=s.getInputStream();
byte[] arr=new byte[is.available()];
int count=0;
count = is.read(arr);
String s1=new String(arr,0,count);
System.out.println(s1);
//4、关闭客户端
s.close();
}
}
        创建服务端:
package Udp;
import java.io.*;
import java.net.*;
public class TcpServer
{
public static void main(String[] args) throws IOException
{
//1、建立服务器Socket明确端口号
ServerSocket ss = new ServerSocket(11000);
//2、利用服务器Socket获取接过来的客户端Socket,用accept()方法
Socket s=ss.accept();
String st=s.getInetAddress().getHostAddress();
System.out.println("连接过来的客户端IP是:"+st);
//3、要么获取输入流,要么获取输出流
OutputStream os=s.getOutputStream();
InputStream is=s.getInputStream();
byte[] arr=new byte[1024*64];
int count =0;
count=is.read(arr);
System.out.println("客户端发送过来的消息是:"+new String(arr,0,count));
os.write("客户端你好啊!".getBytes());
//4、关闭服务端
s.close();
ss.close();
}
}
        例子1:建立一个简单字母转换服务器。
package Udp;
import java.io.*;
import java.net.*;
import java.util.*;
public class CountServer
{
public static void main(String[] args) throws IOException,EmptyStackException
{
ServerSocket ss=new ServerSocket(11001);
Socket s=ss.accept();
BufferedWriter bw =new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
BufferedReader br= new BufferedReader(new InputStreamReader(s.getInputStream()));
String line=null;
while((line=br.readLine())!=null)
{
bw.write(line.toUpperCase());
bw.newLine();
bw.flush();
}
ss.close();
}
}
public class CountClient
{
public static void main(String[] args) throws UnknownHostException, IOException
{
Socket s=new Socket(InetAddress.getLocalHost(),11001);//可以传入IP对象或者IP字符串
PrintWriter pw =new PrintWriter(s.getOutputStream(),true);
BufferedReader br2= new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedReader br1 = new BufferedReader(new InputStreamReader(System.in));
String line=null;
while((line=br1.readLine())!=null)
{
if("over".equals(line))
break;
pw.println(line);
String str=br2.readLine();
System.out.println("经过计算的结果是:"+str);
}
s.close();
br1.close();
}
}
        例子2:上传一个文件!
import java.io.*;
import java.net.*;
public class CountServer
{
public static void main(String[] args) throws IOException
{
ServerSocket ss=new ServerSocket(11002);
Socket s=ss.accept();
PrintWriter pw =new PrintWriter(s.getOutputStream(),true);
BufferedReader br2= new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedWriter br1= new BufferedWriter(new FileWriter("C:\\Users\\彭攀\\Desktop\\彭攀的Java学习日记\\2014-11-30(复件).txt"));
String line=null;
while((line=br2.readLine())!=null)
{
br1.write(line);
br1.newLine();
br1.flush();
}
pw.println("上传成功!");
br1.close();
ss.close();
}
}
import java.io.*;
import java.net.*;
public class CountClient
{
public static void main(String[] args) throws UnknownHostException, IOException
{
Socket s=new Socket(InetAddress.getLocalHost(),11002);//可以传入IP对象或者IP字符串
PrintWriter pw =new PrintWriter(s.getOutputStream(),true);
BufferedReader br2= new BufferedReader(new InputStreamReader(s.getInputStream()));
BufferedReader br1 = new BufferedReader(new FileReader("C:\\Users\\彭攀\\Desktop\\彭攀的Java学习日记\\2014-11-30.txt"));
String line=null;
while((line=br1.readLine())!=null)
{
if("over".equals(line))
break;
pw.println(line);
}
s.shutdownOutput();//告诉服务器我们这里已经发送完毕了!
String str=br2.readLine();//在此处会阻塞!
System.out.println("服务器上传是否成功?"+str);
s.close();
br1.close();
}
}
        例3:通过多线程来上传图片
package udp;
import java.net.*;
import java.io.*;
public class PicThreadServer
{
public static void main(String[] args) throws IOException
{
ServerSocket ss=new ServerSocket(11005);
int count=0;
while(true)
{
Socket s=ss.accept();
new Thread(new PicServer(s)).start();
count++;
if(count>=100)
{
System.out.println("线程太多,服务器资源有限!");
break;
}
}
ss.close();
}
}
class PicServer implements Runnable
{
Socket s;
PicServer(Socket s)
{
this.s=s;
}
public void run()
{
InputStream is;
OutputStream os;
FileOutputStream fos = null;
try
{
is = s.getInputStream();
fos = new FileOutputStream("C:\\Users\\彭攀\\Desktop\\简历.files\\ppphoto(复件).jpg");
int count =0 ;
byte[] arr=new byte[1024];
while((count=is.read(arr))!=-1)
{
fos.write(arr, 0, count);
}
os=s.getOutputStream();
os.write("传输成功".getBytes());
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
s.close();
fos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
}
package udp;
import java.io.*;
import java.net.*;
public class PicThreadClient
{
public static void main(String[] args) throws UnknownHostException, IOException
{
Socket s=new Socket(InetAddress.getLocalHost(),11005);
OutputStream os=s.getOutputStream();
FileInputStream fi=new FileInputStream("C:\\Users\\彭攀\\Desktop\\简历.files\\ppphoto.jpg");
int count=0;
byte[] arr=new byte[1024];
while((count=fi.read(arr))!=-1)
{
os.write(arr,0,count);
}
s.shutdownOutput();
InputStream is=s.getInputStream();
byte[] arr1=new byte[1024];
int num=0;
num=is.read(arr1);
System.out.println("服务端是否上传成功?"+new String(arr1,0,num));
fi.close();
s.close();
}
}

六、自定义客户端-TomCat服务器、浏览器-自定义服务器和浏览器-TomCat服务器

        我们知道浏览器就是一个很好的客户端,现在我们可以利用自己自定义的服务器让浏览器访问它或者自己自定义客户端访问服务器。

        在现实网络中我们都通过浏览器这个客户端来与服务器主机进行数据交换,它们之间建立连接之后服务器主机就会不断的write数据到浏览器上,浏览器解析这些数据然后将有用的数据现实在屏幕上。服务器就是一直在用HTML语言加有用数据进行包装然后写出到客户端,客户端接收。
        现在介绍两种情况:         1、浏览器-自定义服务器。
package udp;
import java.io.*;
import java.net.*;
public class CountServer
{
public static void main(String[] args) throws IOException
{
ServerSocket ss=new ServerSocket(11003);
Socket s=ss.accept();
System.out.println(s.getInetAddress().getHostAddress());
PrintWriter pw =new PrintWriter(s.getOutputStream(),true);
BufferedReader br= new BufferedReader(new InputStreamReader(s.getInputStream()));
String s1=null;
while((s1=br.readLine())!=null)
{
System.out.println(s1);
if(s1.trim().length()<=0)
break;
}
pw.println("客户端你好!");
ss.close();
}
}
        2、浏览器-Tomcat服务器
        这个操作和我们平常的操作没什么不同         3、自定义客户端-Tomcat服务器         浏览器给Tomcat服务器发送了一堆Http协议的请求消息头,然后服务器将自身的网站传送到客户端!
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)
Accept-Encoding: gzip, deflate
Host: 192.168.1.100:11003
Connection: Keep-Alive

七、URl

        URL类代表服务器IP地址和端口的标示符。它的实例化可以在构造函数传入协议,IP,端口,路径,文件等或者它们组合成的字符串,这样以便于在客户端创建Socket并且建立连接。
package udp;
import java.net.*;
public class URLDemo
{
public static void main(String[] args) throws MalformedURLException//格式不对异常
{
URL url=new URL("http://www.baidu.com/s?wd=java%E5%9F%B9%E8%AE%AD&rsv_spt=1&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg");
System.out.println("getProtocol="+url.getProtocol());
System.out.println("getHost="+url.getHost());
System.out.println("getPort="+url.getPort());//若url中没有指定port则返回默认port=-1,然后在建立Socket时过port=-1则重置其为80端口
System.out.println("getPath="+url.getPath());
System.out.println("getFile="+url.getFile());
System.out.println("getQuery="+url.getQuery());
/*
String getFile()
获取此 URL 的文件名。
String getHost()
获取此 URL 的主机名(如果适用)。
String getPath()
获取此 URL 的路径部分。
int getPort()
获取此 URL 的端口号。
String getProtocol()
获取此 URL 的协议名称。
String getQuery()
获取此 URL 的查询部

*/
}
}
        URL还可以调用openConnection返回一个URLConnectiong对象,表示URL所引用的远程对象的连接,从而直接开启连接,然后获取流对象。
package udp;
import java.io.*;
import java.net.*;
public class URLConnectionDemo
{
public static void main(String[] args) throws Exception
{
URL url=new URL("http://www.baidu.com");
URLConnection conn=url.openConnection();//将Socket封装进去了,直接建立了连接,处于应用层对象
System.out.println(conn);
InputStream is=conn.getInputStream();
byte[] arr=new byte[1024*64];
int count=0;
count=is.read(arr);
System.out.println(new String(arr,0,count));//不用关闭
}
}

八、DNS服务器。

        我们一般上网访问服务器,比如百度都只需要输入“www.baidu.com”,而从我们上面的知识可以知道其实我们要输入的是IP地址和端口才能建立连接。我们管“www.baidu.com”叫做域名,当我们在浏览器输入该域名时就需要去一个域名解析服务器去翻译成IP地址返回在建立连接,而域名解析服务器就叫做DNS服务器。

        对于本地IP地址也有一个域名,这个域名存在于C:\Windows\System32\drivers\etc\hosts目录之下,当我们在访问服务器时,需要先访问该目录通过域名查找对应的IP地址,在建立连接,若在该目录下不匹配,再去访问DNS服务器获取匹配的IP地址。所以,如果我们希望强制屏蔽一个网站的话就将该网站的域名在该目录下对应到本地IP地址之上就行了.




------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------