------- android培训、java培训、期待与您交流! ----------
常用的网络模型有两种:OSI参考模型和TCP/IP参考模型,OSI模型分七层分别为应用层、表示层、会话层、传输层、网络层、数据链路层和物理层,对应于TCP/IP模型的应用层、传输层、网络层和物理链路层。Java中的网络传输是基于套接字机制,要进行网络通信必须要指定通信三要素:IP地址、端口号以及遵循的传输协议类型。
一、网络通信三要素:
1、Java中使用InetAddress类对IP地址进行了封装,该对象提供了许多方便调用的静态方法,如getByName()、getAllByName(),getByAddress()、getLocalHost()等静态方法,获取对应主机的IP地址,返回类型为InetAddress或InetAddress[],同时该对象还提供了其他一些有用的非静态方法如getAddress(),getHostAddress()、getHostName()等能够很方便的获取相关信息。
2、端口号:它是用于标识网络应用程序进程的一种逻辑标识,通过它可以知道网络通信的对方是那个应用程序进程。
3、传输协议类型——常用的两个传输协议UDP和TCP,及用户数据报协议和传输控制协议。两者特点总结如下:
UDP:面向无连接的、不可靠的传输协议,而且对传输的数据报大小进行限制,最大不能超过64K,并且传输过程中不能保证数据一定能够到 达收信者,但其传输效率较高,通常用于一些实时性较强的网络通信中,比如实时聊天、视频等。
TCP:面向连接的、可靠的传输协议,保证传输过程中数据报一定到达收信者,而且连接过程要经历三次握手,对数据包的传输大小没有限制 ,可以进行大数据量的传输,但由于传输过程保证了数据的可靠性,使得其传输效率不如udp高,通常用于传输数据的应用程序。
二、网络编程——socket
socket是为了网络服务而提供的一种机制,通信的收发双方都有socket,网络通信实际上就是通信双方之间的socket的通信过程,数据在socket间是通过IO传输的。
1、UDP传输方式:两个重要的类——DatagramSocket用于发送和接收数据的套接字,DatagramPacket用于udp发送和接收数据时对数据包的封装。
udp传输方式进行网络编程的步骤:发送端——创建套接字对象,系统会为其随机分配一个端口号或者可以指定自己的端口号,然后,定义一个数据包,用于填装发送的数据,将发送数据写入数据报,定义一个DatagramPacket对象,将数据大包,并在其构造函数中指明发送端的IP和端口信息。最后,调用套接字的send方法,将数据发送到指定地点。
接收端:首先,定义一个套接字,并制定自己的端口号信息,用作标识发送端数据的目的地;然后,定义一个数据包用作接收数据,创建DatagramPacket对象,并调用套接字的receive方法,将发送来的数据打包给接收端的数据包。
import java.net.*;
import java.io.*;
/*
需求:在发送端通过键盘录入,将数据传输到接收端显示
该程序会对异常进行处理,而是直接抛出。
*/
class UdpChatSend
{
public static void main(String[] args) throws Exception
{
//创建套接字对象
DatagramSocket ds=new DatagramSocket();
//通过键盘录入进行信息交互
BufferedReader bufR=new BufferedReader(new InputStreamReader(System.in));
//byte[] buf=new byte[1024];
String line=null;
while((line=bufR.readLine())!=null)
{
if("over".equals(line))
break;
//定义一个发送数据包
byte[] buf=line.getBytes();
//将发送数据打包给一个DatagramPacket对象,通过该对象指定发送目的端
DatagramPacket dp=new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.1.158"),5001);
//调用send发送将数据发往接收端即可,不保证发送的数据一定接收
ds.send(dp);
System.out.println("192.168.1.158"+"::"+line);
}
bufR.close();
ds.close();
}
}
class UdpChatRecv
{
public static void main(String[] args) throws Exception
{
//创建接收端的套接字对象,并指定其端口号,标识接收方的进程
DatagramSocket ds=new DatagramSocket(5001);
byte[] buf=new byte[1024];
while(true)
{
DatagramPacket dp=new DatagramPacket(buf,buf.length);
//接收发送来的数据,
ds.receive(dp);
//通过DatagramPacket对象,获取发送来的数据
String ip=dp.getAddress().getHostAddress();
String str=new String(dp.getData(),0,dp.getLength());
System.out.println(ip+"::"+str);
}
//ds.close();
}
}
2、TCP传输方式:要分客户端和服务端,在客户端用Socket套接字,服务端则使用ServerSocket套接字进行通信,通过调用套接字的getInputStream()和getOutputStream()方法来获取套接字的输入流和输出流数据,在服务端通过一个阻塞方法accept来不断接受客户端的连接请求,并使用读写流等操作对客户端的数据进行读写操作处理。
步骤:
客户端:1、创建客户端Socket套接字,并将其与目的主机信息进行绑定
2、从数据源中读取数据并写入到套接字输出流中
3、读取套接字中由服务端传过来的确认信息
4、关闭套接字。
服务端:
1、创建服务端socket服务,并监听一个端口。
2、服务端为了给客户端提供服务,获取客户端的内容,可以通过accept方法获取连接过来的客户端对象。
3、可以通过获取到的socket对象中的socket流和具体的客户端进行通讯。
4、如果通讯结束,关闭资源。注意:要先关客户端,再关服务端。
实例:校验登录名,服务端利用多线程技术,不断接收从不同客户端的连接请求,对每一个请求建立新的校验线程,判断用户名的正确性。
import java.net.*;
import java.io.*;
class LoginClient
{
public static void main(String[] args)
{
try
{
//创建客户端套接字对象,并指定服务端地址信息
Socket s=new Socket("192.168.1.158",5003);
//创建读取键盘录入数据的流对象
BufferedReader bufR=new BufferedReader(new InputStreamReader(System.in));
//获取套接字输出流对象,将键盘数据写入到输出流
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
//获取套接字输入流对象,读取服务端的反馈信息
BufferedReader buffReader=new BufferedReader(new InputStreamReader(s.getInputStream()));
String strLine=null;
//最多有三次输入用户名的机会
for(int i=0;i<3;i++)
{
strLine=bufR.readLine();
if(strLine==null)
break;
pw.println(strLine);
//读取服务端反馈信息
String strBack=buffReader.readLine();
if(strBack.contains("successed"))
{
System.out.println(strBack);
break;
}
System.out.println(strBack);
}
s.shutdownOutput();
s.close();
}
catch (Exception e)
{
throw new RuntimeException("Login failed!");
}
}
}
class LoginServer
{
public static void main(String[] args)throws Exception
{
ServerSocket ss=new ServerSocket(5003);
while(true)
{
Socket s=ss.accept();
new Thread(new LoginThread(s)).start();
}
}
}
class LoginThread implements Runnable
{
private Socket s;
LoginThread(Socket s)
{
this.s=s;
}
public void run()
{
String ip=s.getInetAddress().getHostAddress();
try
{
for(int i=0;i<3;i++)
{
//读取硬盘中保存的用户数据信息
BufferedReader bufR=new BufferedReader(new FileReader("user.txt"));
BufferedReader bufS=new BufferedReader(new InputStreamReader(s.getInputStream()));
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
String names=null;
String name=bufS.readLine();
//匹配结束标志
boolean bMatch=false;
while((names=bufR.readLine())!=null)
{
if(name.equals(names))
{
bMatch=true;
break;
}
}
if(bMatch)
{
System.out.println(ip+"Login!");
pw.println("Login successed!");
break;
}
else
{
System.out.println(ip+"failed!");
pw.println("Login failed!");
}
}
s.close();
}
catch (Exception e)
{
throw new RuntimeException("Login failed!");
}
}
}