黑马程序员—网络编程

1.网络模型:OSI参考模型;TCP/IP参考模型。

2.网络通讯要素:

IP地址:(InetAddress)网络中设备的标识;不记忆,可用主机名;本地回环地址:127.0.0.1主机名:localhost。

InetAddress i =InetAddress.getLocalHost();//获取本机计算机名和IP。

InetAddress i =InetAddress.getByName("其他地址");//获取其它IP地址及主机名。

端口号:用于标识进程的逻辑地址,不同进程的标识;有效端口:0~65535,其中0~1024系统使用或保留端口。

传输协议:通讯的规则;常见协议:TCP,UDP。

3.找到对方IP(将数据封包找到后将数据拆包)

       数据要发送到对方指定的应用程序上。为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。为了方便称呼这个数字叫做端口。定义通信规则,这个通信规则称为协议,国际组织定义通用协议TCP/IP。

UDP

(1)将数据即源和目的封装成数据包中,不需要建立连接。

(2)每个数据包的大小限制在64k内

(3)因无连接,是不可靠协议。

(4)不需要建立连接,速度快。

TCP

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

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

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

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

Socket

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

(2)通信的两端都有Socket。

(3)网络通信其实就是Socket间的通信。

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

UDP传输

1.UDP传输流程:创建DatagramSocket(Socket对象)与DatagramPacket(数据包信息);建立发送端,接收端;建立数据包;调用Socket的发送接收方法;关闭Socket。

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

3.定义UDP发送端

思路:

(1)建立udpsocket服务。

(2)提供数据,并将数据封装到数据包中。

(3)通过socket服务的发送功能,将包发出去。

(4)关闭资源。

class UdpSend
{
       publicstatic void main(String[] args) throws Exception
       {
              //1,创建udp服务。通过DatagramSocket对象。
              DatagramSocketds = new DatagramSocket(8888);
              //2,确定数据,并封装成数据包。
DatagramSocket(byte[]buf,int length,InetAddress,int port)
              byte[]buf = "upd ge men lai le ".getBytes();
              DatagramPacketdp =
 newDatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),10000);
              ds.send(dp);//3,通过socket服务,将已有的数据包发送出去。通过send方法。
              ds.close();//4,关闭资源。
       }
}

4.定义UDP接收端

思路:

(1)定义UdpSocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。方便于明确哪些数据过来应该应用程序可以处理。

(2)定义一个数据包,因为要存储接收到的字节数据。因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

(3)通过Socket服务的Receive方法将收到的数据存入已定义好的数据包中。

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

(5)关闭资源。

class UdpRece
{
       publicstatic void main(String[] args) throws Exception
       {
              //1.创建udp Socket,建立端点。
              DatagramSocketds = new DatagramSocket(10000);
              //不能把这句话放到while循环内会使其用一个端口,会出现绑定异常
              while(true)//没有问题能保持接收端一直开启
              {
                     byte[]buf = new byte[1024];//2,定义数据包。用于存储数据
                     DatagramPacketdp = new DatagramPacket (buf,buf.length);
                     //3.通过服务的receive方法将收到数据,存入数据包中。
                     ds.receive(dp);//阻塞式方法。
                     //4,通过数据包的方法获取其中的数据。
                     Stringip = dp.getAddress().getHostAddress();
                     Stringdata = new String (dp.getData(),0,dp.getLength());
                     intport = dp.getPort();
                     System.out.println(ip+"---"+data+":::"+port);
                     ds.close();//5,关闭资源
              }
       }
}

示例:创建一个聊天程序。

import java.io.*;
import java.net.*;
class Send implements Runnable
{
       privateDatagramSocket ds;
       publicSend(DatagramSocket ds)
       {
              this.ds= ds;
       }
       publicvoid run()
       {
              try
              {
                     BufferedReaderbu = new BufferedReader(new InputStreamReader(System.in));
                     Stringline = null;
                     while((line=bu.readLine())!=null)
                     {
                            if("886".equals(line))
                                   break;
                            byte[]bf = line.getBytes();
                            DatagramPacketdp
 = newDatagramPacket(bf,bf.length,InetAddress.getByName("127.0.0.1"),10002);
                            ds.send(dp);
                     }
                     ds.close();
              }
              catch(Exception e)
              {
                     thrownew RuntimeException("发送失败");
              }
       }
}
class Rece implements Runnable
{
       privateDatagramSocket ds;
       publicRece(DatagramSocket ds)
       {
              this.ds= ds;
       }
       publicvoid run()
       {
              try
              {
                     while(true)
                     {
                            byte[]buf = new byte[1024];
                            DatagramPacketdp = new DatagramPacket(buf,buf.length);
                            ds.receive(dp);
                            Stringip = dp.getAddress().getHostAddress();
                            Stringdata=new String(dp.getData(),0,dp.getLength());
                            intport = dp.getPort();
                            System.out.println(ip+"---"+data+"-----"+port);
                     }
              }
              catch(Exception e)
              {
                     thrownew RuntimeException("接收失败");
              }
       }
}
class ChatDemo
{
       publicstatic void main(String[] args) throws Exception
       {
              DatagramSocketsendSocket = new DatagramSocket();
              DatagramSocketreceSocket = new DatagramSocket(10002);
 
              newThread (new Send(sendSocket)).start();
              newThread (new Rece(receSocket)).start();
       }
}

TCP传输

1.TCP传输流程:Socket(创建客户端的Socket服务,指定目的主机和端口)和ServerSocket(建立服务端Socket服务。并监听一个端口);建立客户端和服务端;建立连接后通过Socket中的IO流进数据的传输;关闭Socket。

2.客户端与服务端是两个独立的程序。

3.客户端基本思路:

       客户端需要明确服务器的IP地址以及端口,这样才可以去试着建立连接,如果连接失败,会出现异常。连接成功,说明客户端与服务端建立了通道,那么通过IO流就可以进行数据的传输,而Socket对象已经提供了输入流和输出流对象,通过getInputStream();,getOutputStream;获取即可。与服务器通讯结束后,关闭Socket。

4.定义客户端:发送一个文本数据Hello。

class TcpClient
{
       publicstatic void main(String[] args) throws Exception
       {
              //创建客户端的Socket服务,指定目的主机和端口。
              Sockets = new Socket("127.0.0.1",10003);
              //为了发送数据,应该获取Socket流中的输出流。
              OutputStreamout = s.getOutputStream();
              out.write("Hello".getBytes());
              s.close();
       }
}

5.服务端基本思路:

       服务端需要明确他要处理的数据是从哪个端口进入的。当有客户访问时,要明确是哪个客户端,可通过accept()获取已连接的客户端对象,并通过该对象与客户端通过IO流进行数据传输。当该客户端访问结束,关闭该客户端。

6.定义一个服务端:将接收的数据打印在控制台上。

class TcpServer
{
       publicstatic void main(String[] args) throws Exception
       {
              //建立服务端Socket服务。并监听一个端口。
              ServerSocketss = new ServerSocket(10003);
              //通过accept方法获取连接过来的客户端对象。
              Sockets = ss.accept();
              Stringip = s.getInetAddress().getHostAddress();
              System.out.println(ip+"---connected");
              //获取客户端发送过来的数据,那么要使用客户端对象的读取流来读取数据。
              InputStreamin = s.getInputStream();
              byte[]buf = new byte[1024];
              intlen = in.read(buf);
              System.out.println(newString(buf,0,len));  
              s.close();//关闭客户端
              ss.close();//关闭服务端 
       }
}

7.TCP传输最容易出现的问题:

       客户端连接上服务端,两端都在等待,没有任何数据传输。通过分析得知:因为read方法或者readLine方法是阻塞式的,导致两端等待。

       解决办法:自定义一个结束标记。或者使用shutdownInput,shutdownOutput方法。

示例:上传一个图片

import java.net.*;
import java.io.*;
class PicClient
{
       publicstatic void main(String[] args) throws Exception
       {
              Sockets = new Socket("127.0.0.1",10007);
              OutputStreamout = s.getOutputStream();
              FileInputStreamfi = new FileInputStream("e:\\1.jpg");
              byte[]buy= new byte[1024];
              intline=0;
              while((line=fi.read(buy))!=-1)
              {
                     out.write(buy,0,line);
              }
              s.shutdownOutput();//结束标记
              BufferedReaderbfr =
 new BufferedReader(newInputStreamReader(s.getInputStream()));
              Stringstr = bfr.readLine();
              System.out.println("服务器返回:"+str);
              fi.close();
              s.close();
       }
}
class PicServer
{
       publicstatic void main(String[] args) throws Exception
       {
              ServerSocketss = new ServerSocket(10007);
              Sockets = ss.accept();
 
              Stringip = new String (s.getInetAddress().getHostAddress());
              System.out.println(ip+"----connected");
              
              FileOutputStreamfo = new FileOutputStream("b.jpg");
              InputStreamin = s.getInputStream();
              byte[]buy= new byte[1024];
              intline=0;
              while((line=in.read(buy))!=-1)
              {     
                     fo.write(buy,0,line);
              }
              PrintWriterout1 = new PrintWriter(s.getOutputStream(),true);
              out1.println("上传成功!");
              fo.close();
              s.close();
              ss.close();
       }
}


URL

URL url = new URL("http://127.0.0.1:8080/myweb/demo.html?name=lisi&age=30");

获取URL方法

stringgetProtocol()—http获取此URL的协议名称。

string getHost()—127.0.0.1 获取此URL的主机名(如果适用)。

int getPort()—8080获取此url的端口号。

string getpath()—/myweb/demo.html 获取此url的路径部分。

string getFile()—/myweb/demo.html?name=lisi&age=30 获取此url的文件名。

stringgetQuery()—name=lisi&age=30(用于表单提交) 获取此URL的查询部分。