------- android培训、java培训 、期待与您交流! ----------
在java中支持网络通讯程序的开发,主要提供了两种通讯协议:TCP协议、UDP协议
---可靠的连接传输,使用三次握手的方式完成通讯
---不可靠的连接传输,传输的时候接收方不一定可以接受的到
在java中的所有网络程序的开发类都在java.net包中。
在互联网上的每一台计算机都有一个唯一表示自己的标记,这个标记就是IP地址。
InetAddress类主要标示IP地址,这个类有两个子类:Inet4Address、Iner6Address,一个用于表示IPV4,另一个表示IPV6协议。
package netprac;
import java.net.InetAddress;
public class InetAddressDemo {
public static void main(String args[]) throws Exception{
InetAddress locAdd = null;
InetAddress remAdd = null;
locAdd = InetAddress.getLocalHost();
remAdd = InetAddress.getByName("www.nepu.edu.cn");
System.out.println("本机的IP地址:"+locAdd.getHostAddress());
System.out.println("我们大学的IP地址:"+remAdd.getHostAddress());
System.out.println("本机是否可达:"+locAdd.isReachable(5000));
}
}
URL(Uniform Resource Locator)统一资源定位符,可以直接使用此类找到互联网上的资源(如:一个简单的网页)。
package netprac;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.Scanner;
public class URLDemo {
public static void main(String args[])throws Exception{
URL url = new URL("http","www.nepu.edu.cn",80,"/kygk.html");
InputStream input = url.openStream();
StringBuffer buf = new StringBuffer();
File f = new File("d:"+File.separator+"a.txt");
OutputStream output = new FileOutputStream(f);
Scanner scan = new Scanner(input);
scan.useDelimiter("\n");
String temp = null;
while(scan.hasNext()){
//System.out.println(scan.next()+"\n");
buf.append(scan.next()).append("\n");
}
temp = buf.toString();
byte b[] = temp.getBytes();
output.write(b);
}
}
URLConnection是封装访问远程网络资源一般方法的类,通过它可以建立与远程服务器的连接,检查远程资源的一些属性。
package netprac;
import java.net.URL;
import java.net.URLConnection;
public class URLConnectionDemo {
public static void main(String args[]) throws Exception{
URL url = new URL("http://www.nepu.edu.cn");
URLConnection urlCon = url.openConnection();
System.out.println("内容大小"+urlCon.getContentLength());
System.out.println("内容类型:"+urlCon.getContentType());
}
}
Encoder最早是从电报中而来,使用Encode进行编码,而使用Decoder进行解码操作,在网络中经常存在这样的编码和解码的操作。
package netprac;
import java.net.URLDecoder;
import java.net.URLEncoder;
publicclass CodeDemo {
publicstaticvoid main(String args[]) throws Exception{
String keyWord = "刘丽娜";
String encod = URLEncoder.encode(keyWord,"UTF-8");
System.out.println("编码之后的内容:"+encod);
String decod = URLDecoder.decode(encod,"UTF-8");
System.out.println("解码之后的内容:"+decod);
}
}
在进行网络程序开发时,传递中文的时候往往会需要进行编码和解码的操作。
在Java中使用Socket(即套接字)完成TCP程序的开发,使用此类可以方便的建立可靠的,双向的,持续的,点对点的通讯连接。
在Socket的程序开发中,服务器端使用ServerSocket等待客户端的连接,对于Java的网络程序来讲,每一个客户端都使用一个Socket对象表示。
在JAVA的网络程序中,客户端只要符合连接的通讯协议,那么服务器端都可以进行接收。
ServerSocket类主要用在服务器端程序的开发上,用于接收客户端的连接请求。
在服务器端每次运行时都要使用accept()方法等待客户端连接,此方法执行之后服务器端将进入阻塞状态,直到客户端连接之后程序才可以向下继续执行,此方法的返回值类型是Socket,每一个Socket都表示一个客户端对象。
下面是一个例子:通过ServerSocket类及Socket类完成一个服务器的程序开发,此服务器向客户端输出”Hello World!”的字符串信息。
import java.net.* ;
import java.io.* ;
public class HelloServer{
public static void main(String args[]) throws Exception { // 所有异常抛出
ServerSocket server = null ; // 定义ServerSocket类
Socket client = null ; // 表示客 户端
PrintStream out = null ; // 打印流输出最方便
server = new ServerSocket(8888) ; // 服务器在8888端口上监听
System.out.println("服务器运行,等待客户端连接。") ;
client = server.accept() ; // 得到连接,程序进入到阻塞状态
String str = "hello world" ; // 表示要输出的信息
out = new PrintStream(client.getOutputStream()) ;
out.println(str) ; // 向客户端输出信息
client.close() ;
server.close() ;
}
}
此时编写完服务器端之后,可以直接通过telnet命令进行测试。(open localhost 8888)
但是一般的开发中,不能使用telnet命令直接连接服务器,不方便,可以编写客户端,客户端的编写时主要使用Socket类,实例化Socket类的时候要指定服务器的主机地址和端口号。
import java.net.* ;
import java.io.* ;
public class HelloClient{
public static void main(String args[]) throws Exception { // 所有异常抛出
Socket client = null ; // 表示客 户端
client = new Socket("localhost",8888) ;
BufferedReader buf = null ; // 一次性接收完成
buf = new BufferedReader(new InputStreamReader(client.getInputStream())) ;
String str = buf.readLine() ;
System.out.println("服务器端输出内容:" + str) ;
buf.close() ;
client.close() ;
}
};
我们可以发现,以上的程序需要编写两套代码才可以完成网络程序的开发,那么实际上这个就表示的是C/S架构,服务器/客户端,所以一般这种程序要同时维护两套代码。
还有另外一套架构:B/S,浏览器/服务器,WEB开发的时候用的,这样的程序只需要维护一套代码即可。
上面的程序写完之后,可以发现,服务器运行完一次之后就会退出了,因为它只能接收一次。
Echo程序,是一个网络编程通讯交互的一个经典案例,称为回应程序,即:客户端输入哪些内容,服务器端会再这些内容前加上“ECHO:”并将信息发回给客户端,
import java.net.* ;
import java.io.* ;
public class EchoServer{
public static void main(String args[]) throws Exception { // 所有异常抛出
ServerSocket server = null ; // 定义ServerSocket类
Socket client = null ; // 表示客 户端
BufferedReader buf = null ; // 接收输入流
PrintStream out = null ; // 打印流输出最方便
server = new ServerSocket(8888) ; // 服务器在8888端口上监听
boolean f = true ; // 定义个标记位
while(f){
System.out.println("服务器运行,等待客户端连接。") ;
client = server.accept() ; // 得到连接,程序进入到阻塞状态
out = new PrintStream(client.getOutputStream()) ;
// 准备接收客户端的输入信息
buf = new BufferedReader(new InputStreamReader(client.getInputStream())) ;
boolean flag = true ; // 标志位,表示可以一直接收并回应信息
while(flag){
String str = buf.readLine() ; // 接收客户端发送的内容
if(str==null||"".equals(str)){ // 表示没有内容
flag = false ; // 退出循环
}else{
if("bye".equals(str)){ // 如果输入的内容为bye表示结束
flag = false ;
}else{
out.println("ECHO : " + str) ; // 回应信息
}
}
}
client.close() ;
}
server.close() ;
}
}
继续使用telnet命令验证服务器端程序的使用。
客户端的设计
import java.net.* ;
import java.io.* ;
public class EchoClient{
public static void main(String args[]) throws Exception { // 所有异常抛出
Socket client = null ; // 表示客 户端
client = new Socket("localhost",8888) ;
BufferedReader buf = null ; // 一次性接收完成
PrintStream out = null ; // 发送数据
BufferedReader input = null ; // 接收键盘数据
input = new BufferedReader(new InputStreamReader(System.in)) ;
buf = new BufferedReader(new InputStreamReader(client.getInputStream())) ;
out = new PrintStream(client.getOutputStream()) ;
boolean flag = true ; // 定义标志位
while(flag){
System.out.print("输入信息:") ;
String str = input.readLine() ; // 接收键盘的输入信息
out.println(str) ;
if("bye".equals(str)){
flag = false ;
}else{
String echo = buf.readLine() ; // 接收返回结果
System.out.println(echo) ; // 输出回应信息
}
}
buf.close() ;
client.close() ;
}
};
此程序虽然可以接收多个客户端的连接,但是在同一个时间段上只能有一个客户端使用。
服务器端只能处理一个请求,如果要想让一个服务器可以同时处理多个请求,则就必须加上多线程的操作机制,每一个客户端连接的时候都启动一个新的线程。
此时我们需要完成一个线程类:
import java.net.* ;
import java.io.* ;
public class EchoThread implements Runnable{
private Socket client = null ;
public EchoThread(Socket client){
this.client = client ;
}
public void run(){
BufferedReader buf = null ; // 接收输入流
PrintStream out = null ; // 打印流输出最方便
try{
out = new PrintStream(client.getOutputStream()) ;
// 准备接收客户端的输入信息
buf = new BufferedReader(new InputStreamReader(client.getInputStream())) ;
boolean flag = true ; // 标志位,表示可以一直接收并回应信息
while(flag){
String str = buf.readLine() ; // 接收客户端发送的内容
if(str==null||"".equals(str)){ // 表示没有内容
flag = false ; // 退出循环
}else{
if("bye".equals(str)){ // 如果输入的内容为bye表示结束
flag = false ;
}else{
out.println("ECHO : " + str) ; // 回应信息
}
}
}
client.close() ;
}catch(Exception e){}
}
};
之后服务器端只需要调用此线程的操作即可。
import java.net.* ;
import java.io.* ;
public class EchoThreadServer{
public static void main(String args[]) throws Exception { // 所有异常抛出
ServerSocket server = null ; // 定义ServerSocket类
Socket client = null ; // 表示客 户端
server = new ServerSocket(8888) ; // 服务器在8888端口上监听
boolean f = true ; // 定义个标记位
while(f){
System.out.println("服务器运行,等待客户端连接。") ;
client = server.accept() ; // 得到连接,程序进入到阻塞状态
new Thread(new EchoThread(client)).start() ; // 每一个客户端表示一个线程
}
server.close() ;
}
};
在TCP的所有操作都必须建立可靠的连接,这样一来肯定会浪费大量的系统性能,为了减少这种开销,在网络中又提供了另外一种传输协议——————UDP,不可靠的连接,这种协议在各个聊天工具中被广泛的应用。
在UDP开发中使用DatagramPacket包装一条要发送的信息,之后使用DatagramSocket用于完成信息的发送操作。
包含真实的要发送的信息,称为数据报。
如果要想运行程序,则在数据报的开发中,应该首先保证客户端要打开。
import java.net.DatagramPacket ;
import java.net.DatagramSocket ;
public class UDPClient{
public static void main(String args[]) throws Exception{ // 所有异常抛出
DatagramSocket ds = null ; // 定义接收数据报的对象
byte[] buf = new byte[1024] ; // 开辟空间,以接收数据
DatagramPacket dp = null ; // 声明DatagramPacket对象
ds = new DatagramSocket(9000) ; // 客户端在9000端口上等待服务器发送信息
dp = new DatagramPacket(buf,1024) ; // 所有的信息使用buf保存
ds.receive(dp) ; // 接收数据
String str = new String(dp.getData(),0,dp.getLength()) + "from " +
dp.getAddress().getHostAddress() + ":" + dp.getPort() ;
System.out.println(str) ; // 输出内容
}
};
服务器端的设计:
import java.net.DatagramPacket ;
import java.net.DatagramSocket ;
import java.net.InetAddress ;
public class UDPServer{
public static void main(String args[]) throws Exception{ // 所有异常抛出
DatagramSocket ds = null ; // 定义发送数据报的对象
DatagramPacket dp = null ; // 声明DatagramPacket对象
ds = new DatagramSocket(3000) ; // 服务端在3000端口上等待服务器发送信息\
String str = "hello World!!!" ;
dp = new DatagramPacket(str.getBytes(),str.length(),InetAddress.getByName("localhost"),9000) ; // 所有的信息使用buf保存
System.out.println("发送信息。") ;
ds.send(dp); // 发送信息出去
ds.close() ;
}
};