黑马程序员_毕向东_Java基础_DAY23-24_网络编程

时间:2023-02-11 14:45:46

----------- android培训java培训、期待与您交流! ------------

网络基础知识:

网络参考模型:

黑马程序员_毕向东_Java基础_DAY23-24_网络编程
网际层最常见的协议:IP

传输层最常见的协议:TCP/UDP

应用层最常见的协议:http、ftp

网络通信原理图:

 黑马程序员_毕向东_Java基础_DAY23-24_网络编程

网络通讯要素:

IP地址:InetAddress

  网络中设备的标示

  不易记忆,可用主机名

  本地回环地址:127.0.0.1,主机名:localhost

主机号为0,表示本网络

主机号为255,表示IP多播

端口号:

  用于标示进程的逻辑地址,不同进程的标示

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

80是IE端口,8080是tomcat端口,mysql是3306端口

传输协议:

   通讯的规则

   常见协议:TCP,UDP

 

InetAddress:

java.lang.Object

  |- java.net.InetAddress

此类表示互联网协议 (IP) 地址。

 直接已知子类:

Inet4Address, Inet6Address

 InetAddress没有构造函数!

 static InetAddress getLocalHost()

static InetAddress getByName(String host)//可接受域名或机器名

static InetAddress[] getAllByName(Stringhost) //多服务器

static InetAddress getByAddress(byte[]addr)

static InetAddress getByAddress(Stringhost, byte[] addr)

  调用以上方法可能会抛出java.net.UnknownHostException

  byte[] getAddress()

 String getHostAddress()  //获取IP地址

 String getHostName()     //获取主机名,不一定能拿到

 String getCanonicalHostName()

  重要的两个方法:

getByName

getHostAddress

 getByName()方法可以使用ip地址或者域名

 

在获取百度的ip地址时,可能返回多个IP地址(服务器集群)

这时候使用:

static InetAddress[] getAllByName(Stringhost)

 

使用示例:

import java.net.InetAddress;
import java.net.UnknownHostException;
publicclass IPDemo{

publicstaticvoid main(String[] args) throws UnknownHostException{
//static InetAddress getLocalHost() 返回本地主机的IP地址对象InetAddress
InetAddressinet=InetAddress.getLocalHost();
System.out.println(inet.toString());
//根据IP地址对象获得主机名
System.out.println(inet.getHostName());
//根据IP地址对象获得本机IP地址
System.out.println(inet.getHostAddress());

//static InetAddress getByName(String host) 根据主机名拿到任意一台主机的IP地址对象
InetAddress[]in= InetAddress.getAllByName("www.baidu.com");
/*如果IP地址和对应的主机名没有在网络上,请求主机能找到地址,但是解析不成功。
* 那么其它主机名还是IP地址,以获得IP地址为主 */
for(int i=0;i<in.length;i++){
System.out.println(in[i].getHostName());
System.out.println(in[i].getHostAddress());
}
// InetAddress in=InetAddress.getAllByName("www.baidu.com");
// System.out.println(in.getHostName());//www.baidu.com
// System.out.println(in.getHostAddress());
}
}

 

TCP 与 UDP:

都是传输层协议

 UDP: User Datagram Protocol, 用户数据报协议 

面向无连接

数据封包(数据报)、64k以下

不可靠

速度快 

应用:即时视频传输、聊天软件

适用情景:传输数据有突发性,数据较短,并且对可靠性要求不大,使用这个协议。

 

TCP:Transmission Control Protocol, 传输控制协议

 面向连接,三次握手

适合大量连续数据传输

可靠

速度低

 

总结:

UDP:面向无连接,数据会被封包,包的体积有限制64kb,不可靠,速度快。如聊天,视频     会议,桌面共享。

TCP:面向连接,可靠的,建立通路后可以传输大数据量。如下载

  

Socket:

socket的英文原义是“孔”或“插座”。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。

 在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

 Socket正如其英文原意那样,象一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。

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

 通信的两端都有socket。

网络通信其实就是socket间的通信。

数据在两个socket间通过io传输。

 Socket / ServerSocket --- 传输流

DatagramSocket / DatagramSocket  --- 传输DatagramPacket

 

UDP通信:

DatagramSocket / DatagramPacket

 DatagramSocket用来发送和接收数据报包的套接字,即能发送也能接收,即两端都用的它。

接收:

void receive(DatagramPacket p)

发送:

send(DatagramPacket p)

 发送和接收的都是数据报包,即要把发送和接收的数据都要封装到DatagramPacket对象中。

 DatagramPacket,数据报包对象。用来实现无连接包投递服务。

 使用while(true)循环来循环执行接收端,new接收端Socket对象时,不能放入循环中,否则会出现java.net.BindException,即端口被占用。

  

创建DatagramSocket服务

 使用构造器----

 DatagramSocket() 

 protected DatagramSocket(DatagramSocketImpl impl)

         创建带有指定 DatagramSocketImpl的未绑定数据报套接字。

 DatagramSocket(int port)

         创建数据报套接字并将其绑定到本地主机上的指定端口。

 DatagramSocket(int port, InetAddress laddr)

         创建数据报套接字,将其绑定到指定的本地地址。

 DatagramSocket(SocketAddress bindaddr)

         创建数据报套接字,将其绑定到指定的本地套接字地址。

 

创建数据报包:

使用构造器----创建时要区分用于接收还是用于发送。

 用于接收:

DatagramPacket(byte[] buf, int length)

DatagramPacket(byte[] buf, int offset, intlength)

 用于发送:

DatagramPacket(byte[] buf, int length,InetAddress address, int port)

DatagramPacket(byte[] buf, int offset, intlength, InetAddress address, int port)

DatagramPacket(byte[] buf, int length,SocketAddress address)

DatagramPacket(byte[] buf, int offset, intlength, SocketAddress address)

 

注意:无论接收还是发送,都要将数据放入byte数组中。

     创建DatagramPacket对象,一定要指定byte数组、长度、IP+port,偏移量随便

     IP地址要用InetAddress表示,而不能用String

 

接收和发送都要指定需要处理的byte数组中的长度和偏移量,在发送时还要指定要发送的目的地,用InetAddress+port或者SocketAddress来表示。

 DatagramPacket对象中封装了一些基本信息,可以使用get方法获取。

如:

获取源地址信息:

 InetAddress getAddress() 

 intgetPort()

 SocketAddress getSocketAddress()

 

获取数据信息:

 byte[] getData()

  intgetLength()

 intgetOffset()

  

UDP信息发送思路:

 1.建立DatagramSocket套接字

2.提供数据,将数据转为到byte[]中,并封装到DatagramPacket中,其中包含了目的地信息。

3.使用DatagramSocket的send方法发送数据报:send(DatagramPacket)

4.发送结束后,关闭资源,即使用DatagramSocket的close方法释放套接字,释放底层资源。

 

DatagramSocket ds = new DatagramSocket();//使用由系统分配的随机可用端口进行发送
byte[] buf = "我是信息".getBytes();
DatagramPacket dp =
newDatagramPacket(buf, buf.length,InetAddress.getByName("192.168.1.254"), 10000);
ds.send(dp);
ds.close();


UDP信息接收思路:

 1.建立DatagramSocket套接字,并指定所监听的端口

2.定义一个数据包,用于接收字节数据,并获取其中的信息。

3.使用receive方法将接收到的数据存入已定义好的数据包中。

4.通过数据包对象的特有功能,获取其中的数据和信息。

5.关闭资源。

 

注意:receive方法是一个阻塞式方法

     在为DatagramSocket指定端口时,如果指定的端口被占用,则会抛出java.net.BindException,

     即绑定异常。端口不是即时释放的。

示例:

DatagramSocket ds = newDatagramSocket(10000); //监听10000端口
byte buf = new byte[1024 * 64];
DatagramPacket dp = new DatagramPacket(buf,buf.length);
ds.receive(dp);
String ip =dp.getAddress().getHostAddress();
int port = dp.getPort();
String data = new String(dp.getData(), 0,dp.getLength());

System.out.println(ip + ":" +port + "\n\t" + data);
ds.close();

 

练习:

//:UdpDemo.java
//简单的网络信息发送演示

import java.net.*;

class UdpSend
{
publicstatic void main(String[] args) throws Exception
{

DatagramSocketsocket = new DatagramSocket(8888);
byte[]message = "Hello, Udp".getBytes();
DatagramPacketpacket = new DatagramPacket(message, message.length,InetAddress.getLocalHost(),
10000);
socket.send(packet);
socket.close();
}
}

class UdpReceive
{
publicstatic void main(String[] args) throws Exception{
DatagramSocketsocket = new DatagramSocket(10000);
byte[]buf = new byte[1024];
DatagramPacketpacket = new DatagramPacket(buf, 1024);
socket.receive(packet);
Stringmessage = new String(packet.getData(), 0, packet.getLength());
System.out.println(message);
socket.close();
}
}

 

//:UdpDemo2.java
//发送端从键盘循环录入数据,接收端逐条接收,输入over两端结束socket服务

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

class UdpSend2
{
publicstatic void main(String[] args) throws Exception
{
DatagramSocketds = new DatagramSocket(10000);
BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));
Stringmessage = null;
while((message= br.readLine()) != null){
byte[] buf = message.getBytes();
ds.send(newDatagramPacket(buf, buf.length, InetAddress.getLocalHost(), 10001));
if("over".equalsIgnoreCase(message))
break;
}
br.close();
ds.close();
}
}

class UdpReceive2
{
publicstatic void main(String[] args) throws Exception{
DatagramSocketds = new DatagramSocket(10001);
while(true){
byte[]buf = new byte[1024 * 64];
DatagramPacketdp = new DatagramPacket(buf, buf.length);
ds.receive(dp);
Stringip = dp.getAddress().getHostAddress();
intport = dp.getPort();
Stringmessage = new String(dp.getData(), 0, dp.getLength());
if("over".equalsIgnoreCase(message)){
ds.close();
break;
}
System.out.println(ip+ ":" + port + "\n" + message);
}
}
}

 

TCP通信:

Socket / ServerSocket 

建立客户端 / 服务器端

 Socket()

Socket(InetAddress address, int port)

Socket(String host, int port)

 Socket s = newSocket("192.168.1.254",10003);

//创建成功即代表连接建立成功

//连接建立成功后即创建了I/O流。

//即建立之后流就已经存在了

使用下列方法获取流

 InputStream getInputStream()

 OutputStream getOutputStream()

 

ServerSocket

 1.建立服务器端的socket服务

ServerSocket server = new Socket(10003);

 2.获取连接过来的客户端对象。

 Socket accept()

 此方法是阻塞式方法

 3.客户端如果发来数据,那么服务器端要使用对象的客户端对象,并获取到该客户端对象的读取流来读取数据。

 注意:

文本传输可以加 Buffered。

加了Buffered之后要记得刷新。

在使用readLine方法时,要注意换行。

 练习: 

//: TcpDemo.java
//简单的客户端与服务端通信演示

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

class TcpServer
{
publicstatic void main(String[] args) throws Exception
{
ServerSocketss = new ServerSocket(10001);
Socketsocket = ss.accept();
InputStreamin = socket.getInputStream();
byte[]buf = new byte[1024];
intlen = in.read(buf);
System.out.println(socket.getInetAddress().getHostAddress()+ ":" + socket.getPort() + "..." + new String(buf, 0,len));

OutputStreamout = socket.getOutputStream();
out.write("Hello,Client".getBytes());
ss.close();
}
}

class TcpClient
{
publicstatic void main(String[] args) throws Exception{
Sockets = new Socket(InetAddress.getLocalHost(), 10001);
OutputStreamout = s.getOutputStream();
out.write("Hello,Server".getBytes());

InputStreamin = s.getInputStream();
byte[]buf = new byte[1024];
intlen = in.read(buf);
System.out.println(InetAddress.getLocalHost()+ "..." + new String(buf, 0, len));
s.close();
}
}

 

//: TcpDemo2.java
//客户端通过键盘录入向服务器端发送文本信息,服务端返回其大写形式

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

class TcpServer2
{
publicstatic void main(String[] args) throws Exception
{
ServerSocketss = new ServerSocket(10002);
Sockets = ss.accept();
InputStreamin = s.getInputStream();
OutputStreamout = s.getOutputStream();
byte[]buf = new byte[1024];
intlen = 0;
while((len= in.read(buf)) != -1){
Stringmessage = new String(buf, 0, len);
out.write(message.toUpperCase().getBytes());
}
//ss.close();
}
}

class TcpClient2
{
publicstatic void main(String[] args) throws Exception{
Sockets = new Socket(InetAddress.getLocalHost(), 10002);
OutputStreamout = s.getOutputStream();
InputStreamin = s.getInputStream();
BufferedReaderbr = new BufferedReader(new InputStreamReader(System.in));
Stringbuf = null;
intlen = 0;
byte[]buf2 = new byte[1024];
while(!"over".equals((buf= br.readLine()))){
out.write(buf.getBytes());

len= in.read(buf2);
System.out.println(newString(buf2, 0, len));
}
s.close();
}
}