黑马程序员_Java网络编程

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

java中支持网络通讯程序的开发,主要提供了两种通讯协议:TCP协议、UDP协议

---可靠的连接传输,使用三次握手的方式完成通讯

---不可靠的连接传输,传输的时候接收方不一定可以接受的到

java中的所有网络程序的开发类都在java.net包中。

在互联网上的每一台计算机都有一个唯一表示自己的标记,这个标记就是IP地址。

InetAddress类主要标示IP地址,这个类有两个子类:Inet4AddressIner6Address,一个用于表示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() ;
	}
};






 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值