黑马程序员_网络编程

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

 

网络编程

概述

网络模型 OSI参考模型,TCP/IP参考模型

网络通讯要素 IP地址,端口号,传输协议

两台主机之间通讯:

1,找到对方IP

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

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

OSI参考模型物理层,数据链路层,网络层,传输层,会话层,表示层,应用层

TCP/IP参考模型主机至网络层,网际层,传输层,应用层

IP地址

    网络中设备的标识

    不易记忆,可用主机名

    本地回环地址:127.0.0.1主机名:localhost

端口号

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

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

传输协议

    常见协议:TCP,UDP

net包中,用于描述IP的对象是InetAddress

InetAddress演示如下

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

class IPDemo 
{
	public static void main(String[] args) throws Exception
	{
		//返回本地主机
		InetAddress i = InetAddress.getLocalHost();
		System.out.println(i.toString());
		//返回ip地址字符串
		System.out.println(i.getHostAddress());
		//返回此ip地址的主机名
		System.out.println(i.getHostName());

		//返回任意一台主机的IP地址对象
		InetAddress ia1 = InetAddress.getByName("192.168.242.1");
		InetAddress ia2 = InetAddress.getByName("www.baidu.com");
	}
}

TCPUDP

UDP

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

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

    无连接,是不可靠协议

    不需要建立连接,速度快

TCP

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

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

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

    必须建立连接,效率会较低

Socket

    Socket就是为网络服务提供的一种机制,通信的两端都有Socket,网络之间的通信其实就是Socket之间的通信

UDP传输

    DatagramSocket:此类用来表示传送和接收数据报包的套接字

    DatagramPacket:数据报包用来实现无连接包投递服务

import java.net.*;
/*
需求:通过udp的传输方式,将一段文字数据发送出去
思路:
1,建立udp Socket服务
2,提供数据,并将数据封装到数据包中
3,通过socket服务的发送功能,将数据报发送出去
4,关闭资源
*/
class  UdpSend
{
	public static void main(String[] args) 
	{
		//创建udp服务,通过DatagramSocket
		DatagramSocket ds = new DatagramSocket();

		//确定数据,并封装成数据包
		byte[] buf = "UDP".getBytes();
		DatagramPacket dp = new DatagramPacket(buf,buf.length,InetAddress.getByName("192.168.242.1"),10000);
		
		//通过socket服务,将已有的数据包发送出去。通过send方法
		ds.send(dp);
		
		//关闭资源
		ds.close();

	}
}

/*
需求:
定义一个应用程序,用于接收udp协议传输的数据并处理

思路:
1,定义udp socket服务;通常会监听一个端口。
2,定义一个数据包,因为要存储接收到的字节数据
	数据包对象中有更多的功能可以提取字节数据中的不同数据信息
3,通过Socket服务的receive方法将收到的数据存入已定义好的数据包中
4,通过数据包中的特有功能,将这些不同的数据取出,打印在控制台上
5,关闭资源
*/

class  UdpReceive
{
	public static void main(String[] args) 
	{
		//创建udp socket,建立端点
		DatagramSocket ds = new DatagramSocket(10000);

		//定义数据包。用于存储数据
		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);

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

	}
}


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){     //readLine() 阻塞式方法
			if("bye".equals(line))
				break;
			byte[] buf = line.getBytes();
			DatagramPacket dp = new DatagramPacket(
				buf,buf.length,InetAddress.getByName("192.168.242.1"),10001);
			ds.send(dp);
		}
		ds.close();
	}
}

class UdpReceive2 
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket ds = new DatagramSocket(10001);
		while(true)
		{
			byte[] buf = new byte[1024];
			DatagramPacket dp = new DatagramPacket(buf,buf.length);
			ds.receive(dp);
			// getHostAddress()	返回 IP 地址字符串(以文本表现形式)。
			// getAddress()	返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
			String ip = dp.getAddress().getHostAddress();
			String data = new String(dp.getData(),0,dp.length());
		}
	}
}


一个UDP聊天程序

import java.io.*;
import java.net.*;
/*
编写一个聊天程序
有收数据的部分,也有发数据的部分,这两部分需要同时执行
需要用到多线程技术,一个线程控制收,一个线程控制发

因为收和发的动作是不一致的,所以要定义两个run方法
而且这两个方法要封装到不同的类中
*/

class  Send implements Runnable
{
	private Socket s;
	public Send(Socket s){
		this.s = s;
	}
	public void run(){
		try
		{
			//键盘录入
			BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));

			String line = null;
			while((line=bufr.readLine())!=null){     //readLine() 阻塞式方法
				if("bye".equals(line))
					break;
				byte[] buf = line.getBytes();

				//构造数据包,将长度为buf.length的发送到192.168.242.1指定主机的10002端口
				DatagramPacket dp = new DatagramPacket(
					buf,buf.length,InetAddress.getByName("192.168.242.1"),10002);
				
				//从ds套接字发送dp数据报包
				ds.send(dp);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("发送端失败");
		}
	}
}

class Receive implements Runnable
{
	private Socket s;
	public Receive(Socket s){
		this.s = s;
	}
	public void run(){
		try
		{
			while(true)
			{
				byte[] buf = new byte[1024];
				DatagramPacket dp = new DatagramPacket(buf,buf.length);
				ds.receive(dp);	//阻塞式方法
									
				//获得发送端的ip地址
				String ip = dp.getAddress().getHostAddress();
				//获得发送端的数据
				String data = new String(dp.getData(),0,dp.getLength());

			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("接收端失败");
		}	
	}
}

class Chat
{
	public static void main(String[] args) throws Exception
	{
		DatagramSocket sendSocket = new DatagramSocket();
		DatagramSocket receSocket = new DatagramSocket(10002);
		
		 //建立并开启发送和接收线程
		new Thread(new Send(sendSocket)).start();
		new Thread(new Receive(receSocket)).start();
	}
}


SocketServerSocket

    Socket:此类实现了客户端套接字

    ServerSocket:此类实现服务端套接字

TCP演示

import java.io.*;
import java.net.*;
/*
Tcp分客户端和服务端
1,客户端对应的对象是Socket
2,服务端对应的对象是ServerS
*/

/*
客户端:
通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机
因为tcp是面向连接的,所以在建立socket服务时,就要有服务端存在,并连接成功
形成通路后,在该通道进行数据的传输

需求:给服务端发送一个文本数据,接收服务端的反馈信息

步骤:
1,创建Socket服务,并指向要连接的主机和端口
2,获取socket流中的输出流,将数据写到该流中,通过网络发送给服务端
3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印
4,关闭客户端资源
*/

class  TcpClient
{
	public static void main(String[] args) throws Exception
	{
		//创建Socket服务,并指向要连接的主机和端口
		Socket s = new Socket("192.168.242.1",10003);

		//为了发送数据,应该获取Socket流中的输出流
		OutputStream out = s.getOutputStream();
		out.write("TCP".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();

	}
}
/*
需求:定义端点接收数据打印在控制台上,并给客户端一个反馈信息

服务端
1,建立服务端的socket服务,ServerSocket
	并监听一个端口
2,获取连接过来的客户端对象
	通过ServerSocket的accept方法。没有连接就会等,这个方法是阻塞的
3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据
	并打印在控制台上
4,关闭服务端(可选)

*/
class TcpServer
{
	public static void main(string[] args)throws Exception
	{
		//建立建立服务端的socket服务,并监听一个端口
		ServerSocket ss = new ServerSocket(10003);

		//通过accept方法获取连接过来的客户端对象
		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"------connect");

		//获取客户端发过来的数据,使用客户端对象的读取流来操作
		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("收到信息".getBytes());

		s.close();

	}
}


一个TCP练习

/*
需求:
建立一个文本转换服务器
客户端给服务端发送文本,服务端会将文本转成大写再返回给客户端
客户端可以不断的进行文本转换。当客户端收到over时,转换结束

分析:
客户端
既然是操作设备上的数据,就可以使用IO技术,并按照IO的操作规律来思考
源:键盘录入
目的:网络设备,网络输出流
操作的是文本数据,可以选择字符流

步骤:
1,建立服务
2,获取键盘录入
3,将数据发给服务端
4,获取服务端返回的大写数据
5,结束,关资源
*/
import java.io.*;
import java.net.*;

class  TransClient
{
	public static void main(String[] args) 
	{
		Socket s = new Socket("192.168.242.1",10004);

		//定义读取键盘数据的流对象
		BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		
		//定义目的,将数据写入到socket输出流,发送给服务端
		BufferedWriter bufOut = new BufferedWriter(
			new OutputStreamWriter(s.getOutputStream()));
		
		//定义一个socket读取流,读取服务端返回的大写信息
		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));

		String line = null;
		while((line=bufr.readLine())!=null){
			if("over".equals.line)
				break;
			bufOut.write(line);
			//键盘录入需要做结束标记
			bufOut.newLine();
			bufOut.flush();

			String str = bufIn.readLine();
			System.out.println(str);
		}
		bufr.close();
		s.close();
	}
}
/*
服务端
源:socket读取流
目的:socket输出流
*/

class  TransServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10004);
		Socket s = ss.accept();

		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"------connect");

		//读取socket读取流中的数据
		BufferedReader bufIn = new BufferedReader(
			new InputStreamReader(s.getInputStream()));

		//目的,socket输出流。将大写数据写入到socket输出流,发送给客户端
		BufferedWriter bufOut = new BufferedWriter(
			new OutputStreamWriter(s.getOutputStream()));
		String line = null;
		while((line=bufIn,readLine())!=null){
			bufOut.write(line.toUpperCase());
			bufOut.newLine();
			bufOut.flush();
		}
		s.close();
		ss.close();
	}
}


 多台主机上传文件示例

/*
需求:上传文件
*/

/*
1,客户端:服务端点
2,读取客户端已有的文件数据
3,通过Socket输出流将数据发给服务端
4,读取服务端反馈信息
5,关闭资源
*/

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

class PicClient {

	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		//创建一个流套接字并将其连接到192.168.242.1地址的10002端口号。
		Socket s = new Socket("192.168.242.1",10002);
		
		//创建一个读取文件的流对象
		FileInputStream fis = new FileInputStream("E:\\music\\喜欢音乐\\张宇 - 月亮惹的祸.ape");
		BufferedInputStream bis = new BufferedInputStream(fis);
		
		//返回此套接字的输出流
		OutputStream out = s.getOutputStream();
		
		//定义一个缓冲区,存储得到的字节数据
		byte[] buf = new byte[1024];
		int len = 0;
		while((len=bis.read(buf))!=-1){
			out.write(buf,0,len);
		}
		//告诉服务端,数据已写完
		s.shutdownOutput();
	
		//返回此套接字的输入流,接收服务端的反馈信息
		InputStream in = s.getInputStream();
		byte[] bytes = new byte[1024];
		int num = in.read(bytes);
		//将反馈信息打印在控制台上
		System.out.println(new String(bytes,0,num));
		
		fis.close();
		s.close();		
	}
}

//服务端
class PicServer {

	public static void main(String[] args)throws Exception {
		// TODO Auto-generated method stub
		ServerSocket ss = new ServerSocket(10002);
		while(true){
			//拿到客户端对象
			Socket s = ss.accept();
			
			//将客户端对象封装到线程中,并开始线程
			new Thread(new FileThread(s)).start();
		}
	}
}

//创建一个FileThread类,实现Runnable接口
class FileThread implements Runnable{

	private Socket s;
	FileThread(Socket s){
		this.s = s;
	}
	public void run(){
		int count = 1;
		String ip = s.getInetAddress().getHostAddress();
		try{
			
			System.out.println(ip+"------connect");
			
			InputStream in = s.getInputStream();
			
			//创建一个文件输出流对象,将读取的数据写入到指定的文件中
			File file = new File(ip+"("+(count)+")"+".ape");
			//每个客户端进来都会创建一个File对象,如果重名,count++
			while(file.exists())
				 file = new File(ip+"("+(count++)+")"+".ape");
			
			FileOutputStream fos = new FileOutputStream(file);
			BufferedOutputStream bos = new BufferedOutputStream(fos);
			byte[] buf = new byte[1024];
			int len = 0;
			while((len=in.read(buf))!=-1){
				bos.write(buf,0,len);
			}
			
			//返回s对象的输出流套接字,用来给客户端反馈信息
			OutputStream out = s.getOutputStream();
			out.write("上传成功".getBytes());
			
			fos.close();
			s.close();
		}catch(Exception e){
			throw new RuntimeException(ip+"上传失败");
		}
	}
	
}


 客户端并发登陆的练习

/*
客户端通过键盘录入用户名
服务端对这个用户名进行校验

如果该用户存在,在服务端显示xxx,已登录
并在客户端显示xxx,欢迎光临

如果该用户不存在,在服务端显示xxx尝试登陆
并在客户端显示xxx用户不存在
*/


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

 class LoginClient {

	public static void main(String[] args)throws Exception {
		
		//创建一个流套接字并将其连接到192.168.242.1主机上的10002端口。
		Socket s = new Socket("192.168.242.1",10002);

		//用来键盘录入用户名
		BufferedReader bufr = new BufferedReader(
				new InputStreamReader(System.in));
		
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		
		BufferedReader bufIn = new BufferedReader(
				new InputStreamReader(s.getInputStream()));
		
		//只能录入三次,使用for循环
		for(int x=0; x<3; x++){
			String line = bufr.readLine();
			out.println(line);
			if(line==null)
				break;
			String info = bufIn.readLine();
			//如果用户已登录,返回信息,并结束循环
			if(line.contains("welcom")){
				System.out.println("info "+info);
				break;
			}
			else
				System.out.println("还有"+(2-x)+"次机会");
			
		}
		
		bufr.close();
		s.close();
			
	}
}

class LoginServer {

	public static void main(String[] args) throws Exception{
		ServerSocket ss = new ServerSocket(10002);
		while(true){
			Socket s = ss.accept();
			//为每一个客户端创建一个线程
			new Thread(new UserThread(s)).start();
		}	
	}
}

class UserThread implements Runnable{
	private Socket s;
	UserThread(Socket s){
		this.s = s;
	}
	public void run(){
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"----------connect");
		try {
			//只能接受三次输入
			for(int x=0; x<3; x++){
				//创建缓冲区,用来存储Socket流中发来的数据
				BufferedReader bufIn = new BufferedReader(
						new InputStreamReader(s.getInputStream()));
				
				String name = bufIn.readLine();
				//如果读取的数据为空,跳出循环
				if(name==null)
					break;
				
				BufferedReader bufr = new BufferedReader(
						new FileReader("D:\\MyEclipse 8.5\\workspace\\java2014\\src\\day24\\user.txt"));
				
				//创建一个打印流,用来给客户端反馈信息
				PrintWriter out = new PrintWriter(s.getOutputStream(),true);
				
				String line = null;
				//定义一个标志位,用来判断名字是否存在
				boolean flag = false;
				while((line=bufr.readLine())!=null){
					if(line.equals(name)){
						flag = true;
						break;
					}
				}
				
				if(flag==true){
					System.out.println(name+" 已登录");
					out.println(name+" welcom");
					break;
				}
				else{
					System.out.println(name+" 尝试登陆");
					out.println(name+" 用户名不存在");
				}			
			}
			s.close();
		} catch (FileNotFoundException e) {			
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


URL:类URL代表一个统一资源定位符,它是指向互联网“资源”的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用

 URL的几个常用方法:

 StringgetFile()
          获取此 URL 的文件名。
 StringgetHost()
          获取此 URL 的主机名(如果适用)。
 StringgetPath()
          获取此 URL 的路径部分。
 intgetPort()
          获取此 URL 的端口号。
 StringgetProtocol()
          获取此 URL 的协议名称。
 StringgetQuery()
          获取此 URL 的查询部分。

 

 

 




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值