黑马程序员—java基础学习--网络编程

java语言在网络编程方面一点不比其他语言差,我们日常所接触到的网络方向,java语言一样可以写出来。今天,一起进入java网络编程方向,了解网络传输原理及思路,更好的向日后互联网方向进军。

*网络编程

一、网络如何进行通讯:

1,找到对方的IP

2,数据要发送到对方指定的应用程序上,为了表示这些应用程序,所以给这些网络应用用数字进行标示,为了方便称呼这个数字,叫做端口,逻辑端口。

3,定义通信规则,这个通信规则称为协议。 国际组织定义了通用协议 TCP/IP。

二、网络模型:

-OSI参考模型

-TCP/IP参考模型

黑马程序员—java基础学习--网络编程_第1张图片

三、网络通讯要素:

-IP地址:InetAddress

1,网络中设备的标识

2,不易记忆,可用主机名

3,本地回环地址:127.0.0.1     主机默认名:localhost

IP地址的获取,代码如下:

import java.net.*;

class  IPDemo
{
	public static void main(String[] args) throws Exception
	{
		//获取本地主机对象
		InetAddress i = InetAddress.getLocalHost();
		System.out.println(i.toString());
		//获取主机地址
		System.out.println("address"+i.getHostAddress());
		//获取主机名称
		System.out.println("name"+i.getHostName());
		
		//以此方法为主获取ip地址,因为百度对应的地址并不唯一,所以需要用数组接受。
		InetAddress[] ia = InetAddress.getAllByName("www.baidu.com");			
		for(InetAddress ia1 : ia){
			//获取主机地址
			System.out.println("address:"+ia1.getHostAddress());
			//获取主机名称
			System.out.println("name:"+ia1.getHostName());
		}
	}
}

-端口号

1,用于表示进程的逻辑地址,不同进程的标识

2,有效端口:0~65535,其中0~1024系统使用或保留端口

-传输协议

1,通讯的规则

2,常见协议:TCP,UDP

UDP:面向无连接,如:聊天,视频,桌面共享。

·将数据及源和目的封装成数据包中,不需要建立连接

·每个数据包的大小限制在64k内

·因无连接,是不可靠协议

·不需要建立连接,速度快

TCP:面向有连接,如:电话,下载

·建立连接,形成传输数据的通道

·在连接中进行大数据量传输

·通过三次握手完成连接,是可靠协议

·必须建立连接,效率会降低

四、Socket

1Socket就是为网络服务提供的一种机制

2,通信的两端都有Socket

3,网络通信其实就是Socket间的通信

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

 

如何通过udp传输方式,将一段文字发送并接收?

发送思路:

1,建立udpsocket服务

2,提供数据,并将数据封装到数据包中

3,通过socket服务的发送功能将数据包发送出去

4,关闭资源

 接收思路:

1,定义udpsocket服务,通常会监听一个端口,其实就是给这个接受网络应用程序定义数字标识,方便于明确哪些数据过来该应用程序可以处理

2,定义一个数据包,因为要存储接受到的字节数据,因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。

3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。

4,通过数据包对象的特有功能,将这些不同的数据取出,打印在控制台上。

5,关闭资源。

代码如下:

import java.net.*;

class  UdpSend	
{
	public static void main(String[] args) throws Exception
	{
		//创建udp服务,通过DatagramSocket对象
		DatagramSocket ds = new DatagramSocket(8888);	//不指定端口的话系统随机产生端口
		//确定数据,并封装成数据包
		byte[] data = "udp come on".getBytes();
		DatagramPacket dp = new DatagramPacket(data,data.length,InetAddress.getByName("192.168.0.2"),10000);
		//通过socket服务,将已有的数据包发送出去,通过send方法
		ds.send(dp);
		//关闭资源
		ds.close();
	}
}

class UdpRece
{
	public static void main(String[] args) throws Exception
	{
		//创建udp服务,通过DatagramSocket对象
		DatagramSocket ds = new DatagramSocket(10000);
		while(true)
		{
			//定义数据包,用于存储数据
			byte[] buf = new byte[1024];
			DatagramPacket dp = new DatagramPacket(buf,buf.length);
			//通过服务的receive方法将收到的数据存入到数据包中
			ds.receive(dp);		//阻塞式方法
			//通过数据包的方法获取其中的数据
			String ip = dp.getAddress().getHostAddress();
			String data = new String(dp.getData(),0,dp.getLength());
			int port = dp.getPort();
			System.out.println(ip+":"+data+":"+port);
		}
		//5,关闭资源
		ds.close();
	}
}

TCP传输

-SocketServerSocket

-建立客户端和服务器端

-建立连接后,通过Socket中的IO流进行数据的传输

-关闭Socket

同样,客户端与服务器端是两个独立的应用程序

 

演示tcp传输的客户端和服务端的互访

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

客户端

1,建立socket服务,指定要连接的主机和端口

2,获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端

3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印

4,关闭客户端资源

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

class  TcpClient2
{
	public static void main(String[] args) throws Exception
	{
		//创建客户端的socket服务,指定目的主机和端口
		Socket s = new Socket("127.0.0.1",10005);
		//为了发送数据,应该获取socket流中的输出流
		OutputStream out = s.getOutputStream();
		out.write("hello,TcpServer2".getBytes());
		
		//建立字节输入流,接受服务端发送过来的数据
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		//打印接收过来的数据
		System.out.println(new String(buf,0,len));
		//关闭流
		s.close();
	}
}

服务端:

1,建立服务端的socket服务,通过ServerSocket建立,并监听一个端口

2,获取连接过来的客户端对象,通过ServerSocketaccept方法,没有连接就会等,所以这个方法是阻塞式的

3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流读取发过来的数据,并打印控制台

4,打印过后建立字节输入流,将数据返回给客户端

5,关闭服务端(可选)

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

class TcpServer2
{
	public static void main(String[] args) throws Exception
	{
		//建立服务端socket服务,并监听一个端口
		ServerSocket ss = new ServerSocket(10005);
		//通过accept方法获取连接活来的客户端对象
		Socket s = ss.accept();
		//有客户端连入将ip打印在窗口上
		String ip = s.getInetAddress().getHostName();
		System.out.println(ip+">>>connected");
		//建立读取流读取客户端发来的数据
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		System.out.println(new String(buf,0,len));
		
		//建立输出流,回应客户端的操作
		OutputStream out = s.getOutputStream();
		out.write("well,hello".getBytes());
		
		//关闭服务端(可选)
		ss.close();
		s.close();
	}
}

需求:上传图片

客户端

1,服务端点,

2,读取客户端已有的图片

3,通过socket输出流将数据发给服务端

4,读取服务端反馈信息

5,关闭

服务端:

这个服务端有个局限性,当A客户端连接上以后,被服务端获取到,服务端执行具体流程

这时b客户端连接,只有等待。

因为服务端还没有处理完A客户端的请求,还没有循环回来执行下一次accept的方法

所以暂时获取不到b客户端对象。

那么为了能让多个客户端同时并发访问服务端,

那么服务端最好就是每个客户端封装到一个单独的线程中,这样就可以同时处理多个客户端请求。

 

如何定义线程呢?

只要明确了每一个哭护短要在服务端执行的代码即可,将改代码存入到run方法中

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

class  PicClient
{
	public static void main(String[] args) throws Exception
	{
		//进行强壮性判断
		if(args.length!=1)
		{
			System.out.println("请选择一个就jpg格式的图片");
			return;
		}
		File file = new File(args[0]);
		if(!(file.exists() && file.isFile())
		{
			System.out.println("该文件有问题,不存在或不是文件");
			return;
		}
		if(!file.getName().endsWith(".jpg"))
		{
			System.out.println("图片格式错误,请重新选择");
			return;
		}
		if(file.length()>1024*1024*5)
		{
			Ststen.out.println("文件过大");
			return;
		}
		//网络流socket对象
		Socket s = new Socket("127.0.0.1",10008); 
		//使用IO流关联并读取图片
		FileInputStream fis = new FileInputStream(file);
		//接受服务端返回的数据
		OutputStream out = s.getOutputStream();

		byte[] buf = new byte[1024];
		int len = 0;
		while((len = fis.read(buf))!=-1)
		{
			out.write(buf,0,len);
		}
		//告诉服务端数据已写完
		s.shutdownOutput();
		
		//读取服务端返回的数据
		InputStream in = s.getInputStream();
		byte[] bufIn = new byte[1024];
		int num = in.read(bufIn);
		System.out.println(new String(bufIn,0,num));
		
		//关闭流动作
		fis.close();
		s.close();
	}
}

class PicThread implements Runnable
{
	private Socket s;
	PicThread(Socket s)
	{
		this.s = s;
	}
	public void run()
	{
		int count = 1;
		String ip = s.getInetAddress().getHostAddress();
		try
		{
			System.out.println(ip+"...connected");
			InputStream in = s.getInputStream();

			File file = new File(ip+"("+(count)+")"+".jpg");
			while(file.exists())
			{
				file = new File(ip+"("+(count++)+")"+".jpg");
			}
			FileOutputStream fos = new FileOutputStream(file);
			
			//读取并写入到服务器图片
			byte[] buf = new byte[1024];

			int len = 0;
			while((len = in.read(buf))!=-1)
			{
				fos.write(buf,0,len);
			}
			
			//返回数据
			OutputStream out = s.getOutputStream();
			out.write("上传成功".getBytes());
			
			//关闭流
			fos.close();
			s.close();	
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"上传失败");
		}
	}
}
class  PicServer
{
	public static void main(String[] args) throws Exception
	{

		//建立服务端流数据
		ServerSocket ss = new ServerSocket(10008);

		while(true)
		{		
			Socket s = ss.accept();
			new Thread(new PicThread(s)).start();
		}
	//	ss.close();
	}
}

URL:

URL 代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询。

URL的常用方法:
 String getFile() 
          获取此 URL 的文件名。 
 String getHost() 
          获取此 URL 的主机名(如果适用)。 
 String getPath() 
          获取此 URL 的路径部分。 
 int getPort() 
          获取此 URL 的端口号。 
 String getProtocol() 
          获取此 URL 的协议名称。 
 String getQuery() 
          获取此 URL 的查询部分。 

代码如下:

import java.net.*;

class URLDemo 
{
	public static void main(String[] args) throws MalformedURLException
	{
		URL url = new URL("http://127.0.0.1/myweb/demo.html?name=haha&age=30");
		
		System.out.println("getProtocol():"+url.getProtocol());	//获取协议
		System.out.println("getHost():"+url.getHost());			//获取主机
		System.out.println("getPort():"+url.getPort());			//获取端口,没有指定返回-1
		System.out.println("getPath():"+url.getPath());			//获取路径
		System.out.println("getFile():"+url.getFile());			//获取文件名
		System.out.println("getQuery():"+url.getQuery());		//获取查询的信息
		
		/*
		若返回端口为-1,则默认端口为80,通常用此方法做web开发
		int port = getPort();
		if(port = -1)
			port = 80;
		*/
	}
}

URLConnection:

代表应用程序和 URL 之间的通信链接。此类的实例可用于读取和写入此 URL 引用的资源。

小知识:

www.sina.com.cn 想要将主机名翻译成ip地址,需要域名解析,DNS

http://127.0.0.1:8080

http://localhost:8080

其实127和localhost的映射关系就在本机上。

c:\windows\system32\drivers\ext\host


你可能感兴趣的:(黑马程序员—java基础学习--网络编程)