----------- android培训、java培训、期待与您交流! ------------
传输层最常见的协议:TCP/UDP
应用层最常见的协议:http、ftp
网络通信原理图:
IP地址:InetAddress
网络中设备的标示
不易记忆,可用主机名
本地回环地址:127.0.0.1,主机名:localhost
主机号为0,表示本网络
主机号为255,表示IP多播
端口号:
用于标示进程的逻辑地址,不同进程的标示
有效端口:0~65535,其中0~1024为系统使用或保留端口
80是IE端口,8080是tomcat端口,mysql是3306端口
传输协议:
通讯的规则
常见协议:TCP,UDP
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
都是传输层协议
UDP: User Datagram Protocol, 用户数据报协议
面向无连接
数据封包(数据报)、64k以下
不可靠
速度快
应用:即时视频传输、聊天软件
适用情景:传输数据有突发性,数据较短,并且对可靠性要求不大,使用这个协议。
TCP:Transmission Control Protocol, 传输控制协议
面向连接,三次握手
适合大量连续数据传输
可靠
速度低
总结:
UDP:面向无连接,数据会被封包,包的体积有限制64kb,不可靠,速度快。如聊天,视频 会议,桌面共享。
TCP:面向连接,可靠的,建立通路后可以传输大数据量。如下载
socket的英文原义是“孔”或“插座”。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。
在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
Socket正如其英文原意那样,象一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电, 有的提供110伏交流电,有的则提供有线电视节目。 客户软件将插头插到不同编号的插座,就可以得到不同的服务。
Socket就是为网络服务提供的一种机制。
通信的两端都有socket。
网络通信其实就是socket间的通信。
数据在两个socket间通过io传输。
Socket / ServerSocket --- 传输流
DatagramSocket / DatagramSocket --- 传输DatagramPacket
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();
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);
}
}
}
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();
}
}