黑马程序员-网络编程

黑马程序员-网络编程

 

---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

  概念:

 

     网络模型分两个:OSI(Open System Interconnection开放系统互联)参考模型、TCP/IP参考模型。

     网络传输的要素有三个:ip地址、端口、传输协议。

         ip地址是网络中各种设备的标识,有了ip就能准确的找到某一台设备,它也可以是主机名,因为主机名和ip存在映射关系。

         端口是用于标识进程的逻辑地址,它就是一个整数,范围是0~65535,其中0~1024为系统保留或使用端口。  

 

  传输协议(通讯规则)又分为:

 

        1.UDP协议

            udp协议会将数据及源和目的封装到数据包中,不需要建立连接,每个数据包的大小限制在64k内,因为是面向无连接协议,所以是不可靠的(容易丢失数据),因此也是速度较快的。常见的udp协议应用如:网络视频、聊天、桌面共享。

 

      2.TCP协议

             tcp协议是面向连接的协议,在传输数据前需要通过三次握手来建立通道,从而完成大量数据的传输,正因为要建立连接才可以传输数据,所以它是可靠协议(不会丢失数据),因此也是效率较低的。常见的tcp协议应用如:下载。

 

 常见网络结构:

      1.C/S结构

               该结构的软件,客户端和服务端都需要编写,开发成本较高,且维护较为麻烦。但是这种结构的软件可以在本地分担一部分计算,减轻服务器压力。

 

      2.B/S结构

               该结构的软件,只需要开发服务端,因为客户端都有浏览器取代,而系统就自带了浏览器,所以这种结构相对来说开发和维护成本较低。

        

代码及示例:

    1. UDP协议:

public class UDPSend {

	/**
	 * UDP协议发送端
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		DatagramSocket ds=new DatagramSocket(10087);//用于UDP协议的对象,如果不指定发送端端口,系统会默认随机生成。
		String line=null;
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		while((line=br.readLine())!=null){
			if("over".equals(line))//结束标记,因为是键盘录入。
				break;
			byte[] buf=line.getBytes();
			DatagramPacket packet=new DatagramPacket(buf, 0, buf.length, InetAddress.getByName("127.0.0.1"), 10086);//指定数据包要发送的目的ip或端口号
			ds.send(packet);//发送数据,如果接收端未开启,数据将丢失。
		}
		//关闭发送端                                                                                  
		ds.close();
	}

}

 

public class UDPReceive {

	/**
	 * UDP协议接收端
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
        //创建udp协议,接收端必须指定其监听的端口。
		DatagramSocket ds=new DatagramSocket(10086);
		//创建数据包
		byte[] buf=new byte[1024];
		DatagramPacket packet=new DatagramPacket(buf, buf.length);//如果发送的数据超出该数据包长度,那么超出的部分数据将被遗弃。
		while(true){
			ds.receive(packet);//接受数据,该方法为阻塞式的。该方法每次在接受数据时,会将数据包中数据清空,所以不必每次创建数据包。
			String ip=packet.getAddress().getHostAddress();//获取发送端的ip
			int port=packet.getPort();//获取发送端端口
			System.out.println(ip+":::"+new String(packet.getData(),0,packet.getLength())+"  端口"+port);
		}
	}

}

 用多线程实现udp协议:

//用多线程实现udp发送端
public class Send implements Runnable {
    private DatagramSocket ds;
    public Send(DatagramSocket ds){
    	this.ds=ds;
    }
	@Override
	public void run() {
		try {
			String line = null;
			BufferedReader br = new BufferedReader(new InputStreamReader(
					System.in));
			while ((line = br.readLine()) != null) {
				if ("over".equals(line))// 结束标记,因为是键盘录入。
					break;
				byte[] buf = line.getBytes();
				DatagramPacket packet = new DatagramPacket(buf, 0, buf.length,
						InetAddress.getByName("127.0.0.1"), 10086);// 指定数据包要发送的目的ip或端口号
				ds.send(packet);// 发送数据,如果接收端未开启,数据将丢失。
			}
			ds.close();
		} catch (Exception e) {
		}
		
	}

}
//多线程实现udp接收端
public class Receive implements Runnable {
	private DatagramSocket ds;
    public Receive(DatagramSocket ds){
    	this.ds=ds;
    }
	@Override
	public void run() {
		try {
			// 创建数据包
			byte[] buf = new byte[1024];
			DatagramPacket packet = new DatagramPacket(buf, buf.length);// 如果发送的数据超出该数据包长度,那么超出的部分数据将被遗弃。
			while (true) {
				ds.receive(packet);// 接受数据,该方法为阻塞式的。该方法每次在接受数据时,会将数据包中数据清空,所以不必每次创建数据包。
				String ip = packet.getAddress().getHostAddress();// 获取发送端的ip
				int port = packet.getPort();// 获取发送端端口
				System.out.println(ip + ":::"
						+ new String(packet.getData(), 0, packet.getLength())
						+ "  端口" + port);
			}
		} catch (Exception e) {
		}
	}
}

 

public class UDPTest {

	/**UDP聊天程序,多线程实现发送端和接收端。
	 * @param args
	 * @throws SocketException 
	 */
	public static void main(String[] args) throws SocketException {
		DatagramSocket send=new DatagramSocket(10087);//接收端
		DatagramSocket receive=new DatagramSocket(10086);//发送端
		new Thread(new Send(send)).start();//启动发送端
		new Thread(new Receive(receive)).start();//启动接收端
	}
}

   2.TCP协议:

public class TCPServer {

	/**
	 * TCP服务端 
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
         //创建TCP服务端
		ServerSocket server=new ServerSocket(10086);
		
		//获取客服端Socket对象
		Socket s=server.accept();//阻塞式方法
		
		//获取Soket输入流,读取客户端数据。
		 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
		 
		 //获取Soket输出流,给客户端返回数据。
		 PrintWriter out=new PrintWriter(s.getOutputStream(),true);
		 
		 //读取客户端数据并打印在控制台,并将数据转换后返回给客户端。
		 String line=null;
		 while((line=br.readLine())!=null){
			 System.out.println(line);
			 out.println(line.toUpperCase());
		 }
		 
		 //关闭客户端
		 s.close();
		
		 //关闭服务端
		 server.close();
		 
	}

}
public class TCPClient {

	/**
	 * TCP客户端
	 * @param args
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public static void main(String[] args) throws UnknownHostException, IOException {
            //创建TCP客户端,需要在创建时明确连接。因为TCP协议是面向连接的。如果创建时未指定连接主机,可以通过connect()方法指定。
		   Socket s=new Socket("127.0.0.1",10086);
		   
		   //获取客户端键盘录入
		   BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
		   
		   //获取Scoket中的输出流,保证数据原样性用PrintWriter
		   PrintWriter out=new PrintWriter(s.getOutputStream(),true);//如果为 true,则 println、printf 或 format 方法将刷新输出缓冲区
		   
		   //获取Scoket中输入流,读取从服务端返回的数据。
		   BufferedReader brIn=new BufferedReader(new InputStreamReader(s.getInputStream()));
		   
		   //将客户端输入数据写入到Socket流中
		   String line=null;
		   while((line=br.readLine())!=null){
			   if("over".equals(line))//键盘录入结束标记
				   break;
			   out.println(line);
			   //读取服务端返回的数据
			   String upperStr=brIn.readLine();
			   System.out.println(upperStr);
		   }
		   //关闭资源,System.in不需关闭。这句话其实就是往Socket流中写入结束标记。
		   s.close();
	}

}

TCP上传文件:

public class UploadClient {

	/**
	 * TCP协议上传文件
	 * @param args
	 * @throws IOException 
	 * @throws UnknownHostException 
	 */
	public static void main(String[] args) throws UnknownHostException, IOException {
        //创建客户端
		Socket s=new Socket("127.0.0.1",10086);
		//创建流关联要上传的文件
		BufferedReader br=new BufferedReader(new FileReader("f:\\list.txt"));
		//获取Scoket输出流
		PrintWriter out=new PrintWriter(s.getOutputStream(),true);
		//上传文件
		String line=null;
		while((line=br.readLine())!=null){
			out.println(line);
		}
		//由于文件读完后,没有往Socket流中写入结束标记,所以要告知服务端文件已读完。
		s.shutdownOutput();//往Socket输出流写入结束标记
		
		//获取Socket输入流,读取服务端反馈的信息。
		InputStream in=s.getInputStream();
		byte[] buf=new byte[1024];
		int len=in.read(buf);
		String result=new String(buf, 0, len);
		System.out.println(result);
		
		//关闭资源
		 s.close();
		 br.close();
	}

}
public class UploadServer {

	/**
	 * TCP上传文件服务端
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
         //创建服务端
		 ServerSocket ss=new ServerSocket(10086);
		 //获取客户端
		 Socket s=ss.accept();
		 String ip=s.getInetAddress().getHostAddress();
		 System.out.println(ip+"........connected");
		 //获取Socket输入流读取客户端数据
		 BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
		 //创建流保存客户端数据
		BufferedWriter bw=new BufferedWriter(new FileWriter("f:\\server.txt"));
		//保存数据
		String line=null;
		while((line=br.readLine())!=null){
			bw.write(line);
			bw.newLine();
		}
		//获取Socket输出流,给客户端反馈信息。
		OutputStream out=s.getOutputStream();
		out.write("上传成功!".getBytes());
		
		//关闭资源
		 ss.close();
		 s.close();
		 bw.close();
	}

}

 TCP多线程上传文件:

public class TCPUploadClient {
	/**
	 * TCP多线程上传客户端
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		//创建客户端
		Socket s=new Socket("127.0.0.1",10086);
		//创建流关联上传的文件
		FileInputStream fis=new FileInputStream("f:\\0.jpg");
		//获取Socket输出流
		OutputStream out=s.getOutputStream();
		//上传数据
		int len=0;
		byte[] buf=new byte[1024];
		while((len=fis.read(buf))!=-1){
			out.write(buf,0,len);
		}
		//告诉服务端数据已经写完
		s.shutdownOutput();
		//读取服务端反馈的信息。
		InputStream in=s.getInputStream();
		byte[] bufIn=new byte[1024];
		int lenIn=in.read(bufIn);
		System.out.println(new String(bufIn,0,lenIn));
	}
	
}

 

public class TCPUpload {

	/**
	 * TCP多线程上传服务端
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
        //创建服务端
		ServerSocket ss=new ServerSocket(10086);
		//为了给多个客户服务,所以循环。
		while(true){
			Socket s=ss.accept();
			//为了避免在处理某个客户数据时,其他客户连不上(等待),需要将处理过程封装成单独任务。
			new Thread(new UploadTask(s)).start();
		}
	}

}
//将处理数据的过程单独封装成任务即线程 
public class UploadTask implements Runnable {
    private Socket s;
    public UploadTask(Socket s){
    	this.s=s;
    }
	@Override
	public void run() {
		int count=0;//给服务器上同名文件编号
		String ip=s.getInetAddress().getHostAddress();
		System.out.println(ip+"...........connected");
		File dir=new File("f:\\upload");//创建保存上传文件的目录
		if(!dir.exists()){
			dir.mkdirs();
		}
		File file=new File(dir,ip+".jpg");
		//检查同名文件
		while(file.exists()){
			file=new File(dir,ip+"("+(++count)+").jpg");
		}
		try {
			// 获取Socket输入流读取客户端数据
			InputStream in = s.getInputStream();
			// 创建流保存上传文件
			FileOutputStream fos = new FileOutputStream(file);
			int len=0;
			byte[] buf=new byte[1024];
			while((len=in.read(buf))!=-1){
				fos.write(buf, 0, len);
			}
			//获取Socket输出流,反馈信息给客户端。
			OutputStream out=s.getOutputStream();
			out.write("上传成功!".getBytes());
			//关闭资源
			fos.close();
			s.close();
			
		} catch (Exception e) {
		}
		
	}

}
 

URLConnection对象:

public class URLConnectionDemo {

	/**
	 * 模拟一个简单的浏览器
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		// URLConnection 对象封装了能解析具体协议的对象和Socket
		String urlStr="http://localhost:8080/school/zhonghe.html";
		URL url=new URL(urlStr);
		//获取url连接器
		//URLConnection conn=url.openConnection();
		//InputStream in=conn.getInputStream();
		//获取能解析具体协议的Socket流。
		InputStream in=url.openStream();//openStream()方法是下面方法的缩写: openConnection().getInputStream()

        int len=0;
        byte[] buf=new byte[1024];
        while((len=in.read(buf))!=-1){
        	System.out.println(new String(buf,0,len,"utf-8"));
        }
	}

}


总结:

         TCP、UDP是传输层的协议,而http协议是应用层的协议。在编写基于TCP协议程序时要注意,当往Socket流中写入的数据结束时,应该调用Socket的shutdownOutput或shutdownInput方法在流末尾写入结束标记来告知服务器上传数据已经完毕。如果在基于TCP协议传输过程中出现客户端和服务端相互等待的情况,应该首先考怒是否读到了结束标记。

 

   ---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------

 

      

        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值