------- android培训、java培训、期待与您交流! ----------
网络编程
Java中的.net包提供了网络通信的类和服务。
1.网络模型:OSI参考模型和TCP/IP参考模型。
一般来说开发处于传输层和网际层。应用层为:FTP和HTTP协议等。传输层为:UDP和TCP等。网际层为:IP。通常用户操作的是应用层,而编程人员需要做的是传输层和网际层,用户在应用层操作的数据,经过逐层封包,最后到物理层发送到另一个模型中,再进行逐层解包,最后回到应用层
2.网络通信的要素
- 找到对方IP
- 数据要发送到指定的应用网络上,为了标识这些程序,故给这些网络应用程序都使用数字进行标识。为了方便称呼其为端口,逻辑端口
- 定义通信规则。这个通信规则被称为协议,国际网络通信通用协议TCP/IP。
IP地址在Java中对应的对象是InetAddress。它有几个重要的方法:
- static InetAddress getByName(String host):获取指定主机的IP和主机名。这个方法是静态的,注意到这个类不能直接new对象,只能通过其本身的静态方法得到 本类对象。
- String getHostAddress():返回IP地址字符串文本形式。
- String getHostName():返回IP地址主机名。
- public static InetAddress getLocalHost():返回本地主机。
一个获取指定主机的例子
import java.net.*;
class getIP
{
public static void main(String[] args)throws Exception
{
//获取本机的Address对象
InetAddress ia=InetAddress.getLocalHost();
//打印本机的名字及地址
String name=ia.getHostName();
String address=ia.getHostAddress();
System.out.println(name+" "+address);
//获取指定主机的ip信息
InetAddress i=InetAddress.getByName("127.0.0.1");
String na=i.getHostName();
String add=i.getHostAddress();
System.out.println(name+" "+address);
//当获取的主机返回的对象不唯一时可以使用InetAddress.getAllByName方法,返回的是一个InetAddress数组
}
}
3.TCP与UDP
UDP:
- 不需要建立连接,将数据和源封装在数据包中。
- 每个数据包的大小限制在64k以内,数据超过64k将自动拆分。
- 面向无连接,所以是不可靠协议。
- 因为不需要连接,所以速度快
TCP:
- 需要建立连接,形成数据传输的通道。
- 可以在数据连接中进行大数据量的传输。
- 通过三次握手完成连接,是可靠的协议。
- 必须建立连接,效率稍低。
无论是UDP还是TCP连接,其使用的基类都是Socket类。
4.Socket
Socket是实现两台主机网络通信的端点,使用Socket类及其方法可以轻松完成网络通信的任务。
Socket的常用构造方法:
- public Socket(InetAddress address,int port):创建一个Socket对象并将其连接到指定 IP 地址的指定端口号。
- public Socket(String host,int port):也可以直接给出指定IP和端口来创建Socket对象。
Socket常用方法:
- public InetAddress getInetAddress():返回包含该Socket对象连接主机的InetAddress对象。
- public InputStream getInputStream():返回该Socket对象的输入流,一般用于TCP传输。
- public OutputStream getOutputStream():返回该Socket对象的输出流,一般用于TCP传输。
- public boolean isConnected():测试是否连接成功,连接成功则返回true。
5.UDP通信
Socket有一个可实现子类DatagramSocket用于给UDP通信。
DatagramSocket常用方法:
- public void connect(InetAddress address,int port):连接到指定地址和端口。当连接到远程地址时,包就只能从该地址发送或接收。
- public boolean isConnected():返回连接状态,若已连接则返回true。
- public void send(DatagramPacket p):发送数据报包。DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
- public void receive(DatagramPacket p):接收数据报包。返回的信息会覆盖掉原DatagramPacket的内容。
- DatagramPacket数据报包,这个包包含了将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
- public DatagramPacket(byte[] buf,int length):构造 DatagramPacket,用来接收长度为 length 的数据包。
- DatagramPacket(byte[] buf, int length, InetAddress address, int port) :构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
- public InetAddress getAddress():返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
- public int getPort():返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的。
- public byte[] getData():返回数据缓冲区。
- public int getLength():返回将要发送或接收到的数据的长度。
- public void setAddress(InetAddress iaddr):设置要将此数据报发往的那台机器的 IP 地址。
- public void setPort(int iport):设置要将此数据报发往的远程主机上的端口号。
- public void setData(byte[] buf):为此包设置数据缓冲区。
使用Udp进行通信时:
- 建立两个DatagramSocket,接收端的Socket必须制定一个端口。
- 建立数据包,将数据和接收端的地址和端口都封装进去
- 调用发送端Socket的send方法,将数据包发送出去
- 接收端,通过receive方法接收数据包
- 关闭资源
发送端:
class ChatSend
{
private DatagramSocket ds;
ChatSend()
{
try
{
ds = new DatagramSocket();
}
catch (SocketException e)
{
System.out.println("未建立连接服务");
return;
}
}
public void chat()
{
try
{
byte[] buf = "这是一个小程序".getBytes();
ds.send(new DatagramPacket(buf,buf.length,
InetAddress.getByName("127.0.0.1"),10010));
//将要发送的数据转成数组后打包成DatagramPacket并发送出去
ds.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
接收端:
class ChatReceive
{
private DatagramSocket ds;
ChatReceive()
{
try
{
ds = new DatagramSocket(10000);
}
catch (SocketException e)
{
System.out.println("未建立连接服务");
return;
}
}
public void chat()
{
try
{
byte[] by = new byte[1024*64];
DatagramPacket dp = new DatagramPacket(by,by.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+" "+data);
//获取包内信息
ds.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
6.TCP通信
TCP通信要用到专门的服务端ServerSocket。这个类主要用来接收Socket对象。
ServerSocket构造方法有:
- public ServerSocket(int port):创建绑定到特定端口的SeverSocket对象。
- public Socket accept():从监听端口接收发送过来的Socket对象。
- public int getLocalPort():返回监听的端口地址。
使用TCP通信的一般步骤:
服务端:
- 建立服务端的Socket服务,并监听一个端口;(SeverSocket)
- 获取连接过来的客户端对象,通过SeverSocket的accept方法。该方法为阻塞式方法;
- .客户端如果发送数据,那么服务端就要使用对应的对象,并且使用客户端的对象的读取流来获得数据
- 关闭客户端。
- .关闭服务端(可选)。
class ChatRece
{
private ServerSocket ss= null;
ChatRece()
{
try
{
ss = new ServerSocket(10086);
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void chat()
{
while(true)
{
try
{
Socket s = ss.accept();
new Thread(new ChatServerThread(s)).start();
//每接受一个服务端就新建一个通信。
}
catch (IOException e)
{
System.out.println("建立连接失败");
continue;
}
}
}
}
class ChatServerThread implements Runnable
{
private Socket s;
ChatServerThread(Socket s)
{
this.s = s;
InetAddress ia = s.getInetAddress();
String address = ia.getHostAddress();
System.out.println(address+"已建立连接");//获得客户端的ip信息
}
public void run()
{
try
{
//读取数据,经过获得的Socket对象的读取流读出数据
BufferedReader bfr = new BufferedReader(new InputStreamReader(s.getInputStream()));
String data = null;
while((data = bfr.readLine())!=null)
{
System.out.println(data);
}
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
客户端
- 建立客户端的Socket服务,指定主机和一个端口;
- 为了发送数据要获得Socket中的输入输出流。
- 使用客户端的write方法就可以向服务端发送数据了
- 关闭客户端。
class ChatSe
{
private Socket s= null;
private InetAddress ia =null;
ChatSe(String adress,int port)
{
try
{
ia = InetAddress.getByName(adress);
s = new Socket(ia,port);//建立指定端口的Socket服务
System.out.println("建立连接成功");
}
catch (Exception e)
{
System.out.println("建立连接失败");
return;
}
}
public void chat()
{
try
{
BufferedWriter bfw = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
BufferedReader bfr = new BufferedReader(
new InputStreamReader(System.in));
//信息从键盘输入并传给服务端
String data = null;
while((data = bfr.readLine())!=null)
{
if(data.equals("over"))//设定信息结束标记
break;
bfw.write(data);
bfw.newLine();//必要的,由于readline是不读取/r/n的如果不加这句,
//在服务端就读取不到/r/n,读取就不能结束
bfw.flush();
}
s.shutdownOutput();//关闭客户端的输出流。相当于给流中加入一个结束标记-1.
bfr.close();
s.close();
}
catch(IOException e)
{
System.out.println("发送数据失败");
}
}
}