黑马程序员-JAVA高级(网络编程)PART1

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


这部分的主要知识点:

1.网络编程概述;

2.UDP传输;

3.TCP传输。


一、网络编程概述


1.网络参考模型

OSI参考模型:包括应用层、表示层、会话层、传输层、网络层、数据链路层、物理层七层。

TCP/IP参考模型:包括应用层(对应OSI模型的应用层、表示层和会话层)、传输层(对应OSI模型的传输层)、网际层(对应OSI模型的网络层)、主机至网络层(对应OSI模型的数据链路层和物理层)四层。


2.网络通讯要素

(1)IP地址

IP地址是网络中设备的标识。本地回环地址为127.0.0.1,主机名为localhost。192.168.1.0表示网络段,192.168.1.255表示这个网络段上的广播地址。

表示IP地址的类是InetAddress

import java.net.*;

class IPDemo 
{
	public static void main(String[] args) throws UnknownHostException
	{
		InetAddress i = InetAddress.getLocalHost();//获得本地主机

		System.out.println(i);
		System.out.println(i.getHostName());//获取IP地址的主机名
		System.out.println(i.getHostAddress());//获取IP地址的字符串表现形式

		//在给定主机名的情况下确定主机的IP地址
		InetAddress ia = InetAddress.getByName("www.baidu.com");
		System.out.println(ia.getHostName());
		System.out.println(ia.getHostAddress());

		//在给定主机名的情况下,获取其IP地址组成的数组
		InetAddress[] ias = InetAddress.getAllByName("www.taobao.com");
		for(InetAddress add:ias)
			System.out.println(add.getHostAddress());
	}
}

(2)端口号

端口用于标识进程的逻辑地址。有效端口号是0~65535,其实0~1024为系统使用或保留端口。

(3)传输协议

传输协议表示通讯的规则,常用的协议有UDP和TCP。


3.TCP和UDP

(1)UDP

将数据封装在数据报中;每个数据报的大小限制在64k内;面向无连接,不可靠;传输速度快。

(2)TCP

建立连接,形成传输数据的通道;传输数据量大;连接要“三次握手”,可靠;效率稍低,速度慢。


4.socket(套接字)

socket是为网络服务提供的一种机制,网络通信的两端都有socket,网络通信其实就是socket之间的通信,数据在两个socket之间通过IO传输。



二、UDP传输

两个对象,DatagramPacket表示数据报包,DatagramSocket表示用来发送和接收数据报包的套接字。

传输过程:使用DatagramSocket建立发送端和接收端;使用DatagramPacket建立数据包;调用DatagramSocket的发送接收方法;关闭DatagramSocket对象。


1.UDP传送数据演示

需求:通过UDP传输方式,将一段文字数据发送出去,并在接收端处理数据。

需要建立一个发送端和一个接收端。

import java.net.*;

/*
UDP发送端建立思路:
1.建立UDPSocket服务;
2.将数据封装到数据包中;
3.通过socket服务的发送功能,将数据包发送出去;
4.关闭资源。
*/
class UdpSend 
{
	public static void main(String[] args) throws Exception
	{
		//通过DatagramSocket对象建立socket服务
		DatagramSocket ds = new DatagramSocket();
	
		//获取数据,并通过DatagramPacket对象将数据封装成数据包
		byte[] buf = "udp ge men lai le".getBytes();
		DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.31.1"),10000);

		//通过DatagramSocket对象的send方法,将封装好的数据包发送出去
		ds.send(dp);

		//关闭资源
		ds.close();
	}
}

/*
UDP接收端建立思路:
1.建立socket服务,监听一个端口;
2.建立一个数据包,用来存储接收到的数据;
3.将接收到的数据存入建立好的数据包中;
4.处理数据;
5.关闭资源。
*/
class UdpReceive
{
	public static void main(String[] args) throws Exception
	{
		//通过DatagramSocket对象建立socket服务,监听10000端口
		DatagramSocket ds = new DatagramSocket(10000);

		//通过DatagramPacket对象建立数据包
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf,buf.length);
	
		//通过DatagramSocket对象的receive方法接收数据,并存入建立好的数据包中
		ds.receive(dp);

		//通过DatagramPacket对象处理获取到的数据
		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();
		}
}
必须先运行接收端程序 UdpReceive,再运行发送端程序 UdpSend,才能收到数据。

2.通过UDP将键盘录入的数据发送出去

import java.net.*;
import java.io.*;

class UdpSend2 
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket();

		//读取键盘录入,加入缓冲
		BufferedReader bufr = new BufferedReader(
			new InputStreamReader(System.in));
		String line = null;
		while((line=bufr.readLine())!=null)
		{
			//如果输入的是"over",则停止输入
			if("over".equals(line))
				break;

			//通过DatagramPacket建立数据包,并发送出去
			byte[] buf = line.getBytes();
			DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.31.1"),10000);
			ds.send(dp);
		}

		bufr.close();
		ds.close();
	}
}

class UdpRec2
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket(10000);

		while(true)//不停的接收
		{
			byte[] buf = new byte[1024];
			DatagramPacket dp = new DatagramPacket(buf,buf.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);
		}
	}
}

3.UDP聊天

需求:编写一个聊天程序。

分析:需要有发数据的部分和收数据的部分,这两部分需要同时进行,所以需要用到多线程,一个线程控制发数据,另一个控制收数据。

import java.net.*;
import java.io.*;

class Send implements Runnable
{
	private DatagramSocket ds;
	Send(DatagramSocket ds)
	{
		this.ds = ds;
	}

	public void run()
	{
		BufferedReader bufr = null;
		try
		{
			bufr = new BufferedReader(
				new InputStreamReader(System.in));
			String line = null;
			while((line=bufr.readLine())!=null)
			{
				byte[] buf = line.getBytes();
				DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.31.1"),10001);
				this.ds.send(dp);
				if("bb".equals(line))
					break;
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("发送信息异常");
		}
		finally
		{
			if(bufr!=null)
				try
				{
					bufr.close();
				}
				catch (IOException e)
				{
					throw new RuntimeException("读取流关闭异常");
				}
			this.ds.close();
		}
	}
}

class Rec implements Runnable
{
	private DatagramSocket ds;
	Rec(DatagramSocket ds)
	{
		this.ds = ds;
	}

	public void run()
	{
		try
		{
			while(true)
			{
				byte[] buf = new byte[1024];
				DatagramPacket dp = new DatagramPacket(buf,buf.length);
				this.ds.receive(dp);

				String ip = dp.getAddress().getHostAddress();
				int pt = dp.getPort();
				String data = new String(dp.getData(),0,dp.getLength());

				if("bb".equals(data))
					break;

				System.out.println(ip+"("+pt+")"+":::"+data);
			}
		}
		catch(IOException e)
		{
			e.printStackTrace();
			throw new RuntimeException("接收信息异常");
		}
		finally
		{
			this.ds.close();
		}

	}
}

class ChatDemo 
{
	public static void main(String[] args) throws SocketException
	{
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket recSocket = new DatagramSocket(10001);

		new Thread(new Send(sendSocket)).start();
		new Thread(new Rec(recSocket)).start();
	}
}


三、TCP传输

两个对象,Socket对象表示客户端套接字,ServerSocket对象表示服务器套接字。

传输过程:通过Socket对象建立客户端,ServerSocket对象建立服务端;建立连接受,通过Socket中的IO流进行数据传输;关闭Socket


1.TCP传输数据演示

import java.io.*;
import java.net.*;

class TcpClient 
{
	public static void main(String[] args) throws Exception
	{
		//创建socket服务,并指定要连接的主机和端口
		Socket s = new Socket("192.168.31.1",10003);
		
		//从socket中获取字节输出流
		OutputStream out = s.getOutputStream();

		//将数据写出去
		out.write("tcp传送数据".getBytes());

		//关闭资源
		s.close();
	}
}

class TcpServer
{
	public static void main(String[] args) throws Exception
	{
		//建立服务端的socket服务,监听一个端口
		ServerSocket ss = new ServerSocket(10003);
		
		//获取连接过来的客户端对象,阻塞式方法
		Socket s = ss.accept();

		//通过获取的客户端对象,获取数据
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+" connected...");

		byte[] buf = new byte[1024];
		InputStream in = s.getInputStream();
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));

		//关闭资源
		s.close();
		ss.close();//可选
	}
}
同样是需要先运行服务端程序。


2.服务端反馈信息到客户端

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

import java.io.*;
import java.net.*;

class TcpClient2 
{
	public static void main(String[] args) throws Exception
	{
		//建立客户端socket服务,指定连接的主机和端口
		Socket s = new Socket("192.168.31.1",10004);

		//获取socket的输出流,向服务端发送数据
		OutputStream out = s.getOutputStream();
		out.write("服务端你好!".getBytes());

		//获取socket的输入流,读取服务端的反馈数据
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));

		//关闭资源
		s.close();
	}
}

class TcpServer2
{
	public static void main(String[] args) throws Exception
	{
		//建立服务端socket服务,监听端口
		ServerSocket ss = new ServerSocket(10004);
	
		//获取链接过来的客户端对象
		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+" connected...");
		
		//获取socket的输入流,读取传送过来的数据
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));

		//获取socket的输出流,向客户端反馈数据
		OutputStream out = s.getOutputStream();
		out.write("客户端哥们你好,我收到了!".getBytes());

		s.close();
		ss.close();
	}
}

3.TCP练习

需求:建立一个文本转换服务器。客户端给服务端发送文本,服务端将文本转换成大写再发送回客户端。可以不断地进行转换,直到客户端输入"over",转换结束。

因为操作的是文本数据,所以考虑使用字符流,并加入缓冲。

import java.io.*;
import java.net.*;

class TransTextClient 
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.31.1",10005);

		BufferedReader bufr = new BufferedReader(
			new InputStreamReader(System.in));

		//BufferedWriter bufOut = new BufferedWriter(
		//	new OutputStreamWriter(s.getOutputStream()));
		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);

		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));
		String line = null;
		while((line=bufr.readLine())!=null)//读取一行数据
		{
			if("over".equals(line))
				break;

			//out.write(line.getBytes());
			//bufOut.write(line);
			//bufOut.newLine();
			//bufOut.flush();
			pw.println(line);//将一行数据发送到服务端

			//从服务端获取返回的数据
			String str = bufIn.readLine();
			System.out.println("server:"+str);
		}
		
		s.close();
		bufr.close();

	}
}

class TransTextServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10005);

		while(true)//服务端不关闭
		{
			Socket s = ss.accept();
			String ip = s.getInetAddress().getHostAddress();
			System.out.println(ip+" connected...");

			BufferedReader bufIn = new BufferedReader(
				new InputStreamReader(s.getInputStream()));

			//BufferedWriter bufOut = new BufferedWriter(
			//	new OutputStreamWriter(s.getOutputStream()));
			PrintWriter pw = new PrintWriter(s.getOutputStream(),true);
			
			//读取客户端发送过来的数据
			String line = null;
			while((line=bufIn.readLine())!=null)
			{
				System.out.println(line);
				//out.write(data.toUpperCase().getBytes());
				//bufOut.write(line.toUpperCase());
				//bufOut.newLine();
				//bufOut.flush();
				pw.println(line.toUpperCase());//将数据转成大写,并发回客户端
			}
			s.close();
			System.out.println(ip+" disconnected...");
		}

	}
}
以上代码可能出现客户端和服务端都在等待的问题,这是因为客户端和服务端都有阻塞式的读取方法,在没有读到结束标记的时候就都一直等待。


4.TCP复制文件

import java.io.*;
import java.net.*;

class UploadTextClient 
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.31.1",10007);

		//System.out.println("nimei");

		BufferedReader bufr = new BufferedReader(
			new FileReader("client.txt"));

		PrintWriter pw = new PrintWriter(s.getOutputStream(),true);

		String line = null;
		while((line=bufr.readLine())!=null)
		{
			pw.println(line);
		}
		/*
		  关闭客户端的输出流,相当于在流中加入一个结束标记-1
		  否则服务端的读取流读不到结束标记而一直处于等待,
		  客户端读不到服务端的返回数据也一直处于等待。
		*/
		s.shutdownOutput();

		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));
		System.out.println(bufIn.readLine());
	
		bufr.close();
		s.close();
	}
}

class UploadTextServer 
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10007);

		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+" connected...");

		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));
		PrintWriter pw = new PrintWriter(new FileWriter("server.txt"),true);
		
		String line = null;
		while((line=bufIn.readLine())!=null)
		{
			pw.println(line);
		}

		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		out.println("上传成功");

		pw.close();
		s.close();
		ss.close();
	}
}

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

详细请查看:http://edu.csdn.net

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值