黑马程序员-java网络编程

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


   计算机网络是分布在不同地理区域上的计算机用通信线路互连气啦的一个具有强大功能的网络体系。
网络分为7层,分别是物理层,数据链路层,网络层,传输层,回话层,表示层和应用层。每一层使用下一层的服务,并为上层提供服务。

不同主机之间的系统层成为对等层,各层的具体含义如下:

物理层(Physical Layer):

传输数据的物理介质,如双绞线和同轴电缆等。物理层的任务就是为它的上一层提供物理连接,
以及规定通信节点之间的机械和电器特性。

数据链路层(Data Link Layer):
数据链路层负责在两个相邻节点间的线路上无差错地传送以帧为单位的数据。每一帧包括一定数量的数据和
一些必要的控制信息。数据链路层要负责建立,维持和释放数据链路的连接。

网络层(Network Layer):
在计算机网络中进行通信的两个计算机之间可能会经过很多歌数据链路,也可能要经过很多通信子网。
网络层的任务就是选择合适的网络路由和交换节点,确保数据及时传送到目标主机。网络层将数据链路层提供
的帧组成数据包,包中封装有层包头,包头中含有逻辑地址信息--源主机和目标主机的网络地址。

传输层(Transport Layer):
该层的任务是根据通信子网的特性最佳的利用网络资源,为两个端系统(也就是源主机和目标主机)的会话层提供
建立,维护和取消传输的功能,以可靠方式把源主机发送的数据正确地送到目标主机。

会话层(Session Layer):
会话层管理进程之间的会话过程,即负责建立,管理,终止进程之间的会话,会话层还通过在数据中插入校验点来实现数据的同步。

表示层(Presentation Layer):
表示层对上层数据进行转换,以保证一个主机的应用层的数据可以被另一个主机的应用层理解。表示层的数据转换包括对数据的加密,
解密,压缩,解压和格式转换灯。

应用层(Application Layer):
应用层确定进程之间通信的实际用途,以满足用户实际需求。浏览web网站,收发E-MAIL,上传和下载文件,以及远程登录服务器等
可以看做是进程之间通信的实际用途。

网络通讯要素:
1,IP地址。
2, 端口号。
3,传输协议。

通信过程:
1,找到对方IP
2,数据要发送到对方指定的应用程序上,为了标识这些应用程序,所以给这些网络应用程序都用数字进行标识。
为了方便称呼这个数字,叫做端口,也称逻辑端口。
3,定义通信规则,这个通信规则称为协议。国际组织定义了通用协议 TCP/IP。

IP地址(InetAddress):
1.网络设备中设备的标识。
2.不易记忆,可用主机名。
3.本地回环地址:127.0.0.1 主机名:localhost

端口号:
1,用于标识进程的逻辑地址。
2, 有效端口:0-65535,其中0-1024系统使用或保留端口。

传输协议:
1.通讯的规则
2.常见协议:TCP,UDP;

在java中,传输层向应用层提供了套接字Soket接口,Soket封装了下层的数据传输细节,应用层的程序通过Socket建立与远程主机的连接,以及进行数据传输。
1,Socket就是为网络服务提供的一种机制
2,通信的两端都有Socket
3,网络通信其实就是Socket间的通信

4,数据在两个Socket间通过IO传输


UDP传输:
1.DatagramSocket于DatagramPacket
2.建立发送端,接收端
3.建立数据包
4.调用Socket的发送接收方法
5.关闭Socket

发送端于接受端是两个独立的运行程序。

发送数据过程:
1.建立udpsocket服务,
2.提供数据,并将数据封装到数据包中,并指定要发送的主机和端口号
3.通过socket服务的发送功能。将数据包发送出去。
4.关闭资源

接收数据过程:
1.定义udpsocket服务并指定要接受数据的端口号
2.定义一个数据包,以为要存储收到的数据,因为数据包对象中有更多的功能可以提起字节数据中的不同信息。
3.通过socket服务的recieve方法将收到的数据存入已定义号的数据包中
4.通过数据包对象的特有功能,将这些不同的数据取出。
5.关闭资源。

UDP传输的简单例子:

//发送端

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class UdpSend
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket();    //建立udpsocket服务
		
		byte[] data = "udp is coming".getBytes();
		DatagramPacket dp = new DatagramPacket(data, data.length, InetAddress.getByName("127.0.0.1"), 10002);  //数据封包
		
		ds.send(dp);    //数据发送
		
		ds.close();	//关闭资源	
	}
}</span>

//接受端

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class UdpRece
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket(10002);    //建立udpsocket服务
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf, buf.length);   //要存放数据的数据包
		ds.receive(dp);                                          //接受数据至数据包
		String ip = dp.getAddress().getHostAddress();            //得到IP地址
		String data = new String(dp.getData(),0,dp.getLength());   //得到数据包中的数据
		int port = dp.getPort();                                  //得到端口号
		System.out.println(ip+":::"+data+":::"+port);           //打印
		ds.close(); //关资源
	}
}</span>

用UDP传输做一个简单的聊天程序,开启两个线程分别负责发送和接收数据。
//发送端

class Send implements Runnable
{
	private DatagramSocket ds;
	Send(DatagramSocket ds )
	{
		this.ds = ds;
	}
	
	public void run() 
	{
		try 
		{
			BufferedReader bufReader = new BufferedReader(new InputStreamReader(System.in));   //键盘录入字符流
			String line = null;
			while((line = bufReader.readLine()) != null)//将键盘录入数据封包发送出去
			{
				if("886".equals(line))
					break;
				byte[] buf = line.getBytes();
				DatagramPacket dPacket = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 10002);
				ds.send(dPacket);
			}
			
		} catch (Exception e)
		{
			throw new RuntimeException("send failed");
		}
	}
}


//接收端

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Rece implements Runnable
{
	private DatagramSocket ds;
	Rece(DatagramSocket ds )
	{
		this.ds = ds;
	}
	
	public void run() 
	{
		try 
		{
			while(true)
			{
				byte[] buf = new byte[1024];
				DatagramPacket dp = new DatagramPacket(buf, buf.length); 
				ds.receive(dp);           //获得发送端数据并封包
				String ip = dp.getAddress().getHostAddress();
				String data = new String(dp.getData(),0,dp.getLength());
				System.out.println(ip+"::"+data);        //打印
			} 
			
		} catch (Exception e) 
		{
			throw new RuntimeException("receive failed");
		}
	}
}</span>

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class udpChat 
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket receSocket = new DatagramSocket(10002);

		//开启发送和接收两个线程
		new Thread(new Rece(receSocket)).start();
		new Thread(new Send(sendSocket)).start();
	}
}</span>

TCP传输:
客户端建立过程:
1.建立socket服务,指定要连接的主机和端口
2.获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端。
3.获取socket流中的输入流,获取服务端反馈的数据。
4.关闭客户端资源。

服务端建立过程:
1.建立服务
2.获取客户端对象
3.获取socket流中的输入流,获取客户端发过来的数据。
4.获取socket流中的输出流,将数据写到该流中,通过网络发送给服客户端。
5.关闭服务端资源。

下面的例子是开启客户端和服务端线程,客户端通过键盘录入字符串发给服务端,服务端将字符串反转反馈给客户端。
//实现客户端的类

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Client implements Runnable
{
	BufferedReader reader = null;  //读入键盘缓冲流
	Socket socket = null;          
	DataOutputStream dos = null;    //客户端输出流
	DataInputStream dis = null;
	public Client() 
	{
		try 
		{
			reader = new BufferedReader(new InputStreamReader(System.in));			
			//连接上10002号端口
			socket = new Socket("127.0.0.1", 10002);				
			//取得客户端输出流
			dos = new DataOutputStream(socket.getOutputStream()); 
			dis = new DataInputStream(socket.getInputStream());
		}
		catch (Exception e) 
		{
			throw new RuntimeException("connect failed!!");
		}

	}	
	public void run()
	{
		try 
		{
				System.out.println("input the message as Client : ");
				String line = reader.readLine();
				while(line != null)
				{
					if("quit".equals(line))
						break;					
					//写入服务器端
					dos.writeUTF(line);				
					//刷新
					dos.flush();					
					String value = dis.readUTF();					
					System.out.println("receive reversed message: "+value);					
					//继续读键盘录入
					line = reader.readLine();
				}
				
				reader.close();
				socket.close();
				dis.close();
				dos.close();
		} 
		catch (IOException e) 
		{
			throw new RuntimeException("send failed!!");
		}
	}		
}</span>

//实现服务器端的类

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Server implements Runnable
{
	
	ServerSocket server = null;		
	Socket socket = null;
	DataInputStream dis = null;
	DataOutputStream dos = null;
	public Server() 
	{
		try 
		{
			server = new ServerSocket(10002);
		}
		catch (Exception e) 
		{
			throw new RuntimeException("connect the client failed!!");
		}
	}

	public void run() 
	{
		try 
		{  //侦听并接受到此套接字的连接		
			socket = server.accept();				
			//获得客户端输入流,转化成DataInputStream流
			dis = new DataInputStream(socket.getInputStream());
			dos = new DataOutputStream(socket.getOutputStream());
		} 
		catch (IOException e1)
		{
			throw new RuntimeException("connect client fialed!!!");
		}
		while(true)
		{
			try
			{	//获得客户端发过来的数据
				String string = reverseString(dis.readUTF());
				dos.writeUTF(string);
			} 
			catch (Exception e) 
			{	//捕捉客户端退出报的异常并退出循环			
				System.out.println("client quit!!");
				break;
			}
		}		
		//退出循环后,关闭服务端和流。
		try 
		{
			if(server != null)
				server.close();
			
			if(socket != null)
				socket.close();
			if(dos != null)
				dos.close();
			
			if(dis != null)
				dis.close();
		}
		catch (Exception e2)
		{
			
		}
	}	
	//反转字符串的函数
	public String reverseString(String str)
	{
		char[] oldChar = str.toCharArray();
		for(int i=0; i<str.length()/2; i++)
		{
			swap(oldChar, i, str.length()-i-1);
		}
		
		return String.valueOf(oldChar);
	}
	//交换数组中字符位置的函数
	public void swap(char[] chs,int i,int j)
	{
		char temp = chs[i];
		chs[i] = chs[j];
		chs[j] = temp;
	}
}</span>
//测试

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class TcpTest
{
	public static void main(String[] args)
	{
		//先启动服务端线程
		new Thread(new Server()).start();
		//再启动客户端线程
		new Thread(new Client()).start();
	}
}</span>
客户端并发上传图片:
在我的g:\java目录下有以数字命名的5个jpg图片文件,现启动5个线程并发连接上服务端上传图片数据,服务端将数据重新写入到g:\java目录下。

//处理图片数据的服务端线程

<span style="font-family:KaiTi_GB2312;font-size:18px;">class PicThread implements Runnable
{
	private Socket socket;	
	public PicThread(Socket socket)
	{
		this.socket = socket;
	}	
	public void run()
	{
		int count = 1;
		String ip = socket.getInetAddress().getHostAddress();
		try 
		{
			System.out.println("ip connect............");
			//获得socket输入流
			InputStream in = socket.getInputStream();
			//创建一个文件,用于将数据写入此文件
			File file = new File("g:\\java\\"+ip+"("+(count)+")"+".jpg");
			while(file.exists())
				file = new File("g:\\java\\"+ip+"("+(count++)+")"+".jpg");	
			//获得文件输出流	
			FileOutputStream fout = new FileOutputStream(file);
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = in.read(buf)) != -1)
			{
				fout.write(buf, 0, len);
			}
			//获得socket输出流
			OutputStream out = socket.getOutputStream();
			//若没出现异常,想客户端发送‘上传成功’。
			out.write("上传成功".getBytes());
			in.close();
			fout.close();
			socket.close();
		} 
		
		catch (Exception e) 
		{
			throw new RuntimeException("上传失败");
		}
	}
	
}</span>

不断监听是否有客户端连接上,如有,启动一个线程去处理客户端发过来的图片数据。

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class Server
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket serverSocket = new ServerSocket(10002);
		while(true)
		{
			Socket socket = serverSocket.accept();
			new Thread(new PicThread(socket)).start();
		}
	}
}</span>

-------------------------------------------------------------------------------------------------------

//发送数据的客户端线程

<span style="font-family:KaiTi_GB2312;font-size:18px;">class Client11 implements Runnable
{
	private int no;
	Socket socket;
	Client11(int no)
	{
		try
		{
			socket = new Socket("127.0.0.1",10002);
		} catch (Exception e) 
		{
			throw new RuntimeException("连接失败");
		}

		this.no = no;
	}
	public void run() 
	{
		try 
		{
			//获得要上传的图片文件
			File file = new File("g:\\java\\"+no+".jpg");
			//获得文件输入流
			FileInputStream in = new FileInputStream(file);
			//获得socket输出流,将图片文件数据写入socket输出流。
			OutputStream out = socket.getOutputStream();
			byte[] buf = new byte[1024];
			int len = 0;
			while((len = in.read(buf)) != -1)
			{
				out.write(buf, 0, len);
			}
			socket.close();
			in.close();
			out.close();
		} catch (Exception e) 
		{
			throw new RuntimeException("发送失败");
		}
	}
}</span>

//客户端将图片数据发送给客户端,启动5个线程进行发送。(图片文件的名字为:数字.jpg)

<span style="font-family:KaiTi_GB2312;font-size:18px;">public class clientTest 
{
	public static void main(String[] args)
	{
		for(int i=1; i<=5; i++)
		{
			new Thread(new Client11(i)).start();
		}
	}
}</span>
先运行服务端,再运行客户端。这个例子模拟了多客户并发登陆,服务端在连接到一个客户端之后 便启动一个线程去处理此客户端的请求。


---------------------- ASP.Net+Unity开发.Net培训、期待与您交流! ----------------------详细请查看:www.itheima.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值