黑马程序员---------网络编程

----------Android培训java培训、期待与您交流-----------


网络编程


一、网络模型和网络通讯要素
网络模型
    OSI参考模型
    TCP/IP参考模型
网络参考模型图

javaWeb开发在应用层

网络通讯要素

IP地址:InetAddress
    网络中设备的标识
    不易记忆,可用主机名
    本地回环地址:127.0.0.1 主机名:localhost
端口号
    用于标识进程的逻辑地址,不同进程的标识
    有效端口:0~65535,其中0~1024系统使用或保留端口。
传输协议
    通讯的规则
    常见协议:TCP,UDP
//获取本地主机
    InetAddress i = InetAddress.getLocalHost();
//返回 IP 地址字符串
    i.getHostAddress()
// 获取此 IP 地址的主机名
    i.getHostName()
//在给定主机名的情况下确定主机的 IP 地址
    InetAddress ia = InetAddress.getByName("thinkpad-sl400");
UDP和TCP
UDP
    将数据及源和目的封装成数据包中,不需要建立连接
    每个数据报的大小在限制在64k内
    因无连接,是不可靠协议
    不需要建立连接,速度快
TCP
    建立连接,形成传输数据的通道。
    在连接中进行大数据量传输
    通过三次握手完成连接,是可靠协议
    必须建立连接,效率会稍低

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

二、UDP
UDP传输步骤:
DatagramSocket与DatagramPacket
发送端:
  1、建立updsocket服务。
  2、提供数据,并将数据封装到数据包中。
  3、通过socket服务的发送功能,将数据包发出去。
  4、关闭资源。
发送端与接收端是两个独立的运行程序
代码:
<span style="font-size:14px;">public static void main(String[] args) throws Exception
{
	//1,创建udp服务。通过DatagramSocket对象。
	DatagramSocket ds = new DatagramSocket(8888);
	//2,确定数据,并封装成数据包。DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
	byte[] buf = "udp ge men lai le ".getBytes();
	DatagramPacket dp = 
		new DatagramPacket(buf,buf.length,InetAddress.getByName("182.32.4.18"),10000);
	//3,通过socket服务,将已有的数据包发送出去。通过send方法。
	ds.send(dp);
	//4,关闭资源。
	ds.close();
}</span>

接收端:
    1、定义udpsocket服务。通常会监听一个端口。其实就是给这个接收网络应用程序定义数字标识。
    方便于明确哪些数据过来该应用程序可以处理。
    2,定义一个数据包,因为要存储接收到的字节数据。
    因为数据包对象中有更多功能可以提取字节数据中的不同数据信息。
    3,通过socket服务的receive方法将收到的数据存入已定义好的数据包中。
    4,通过数据包对象的特有功能。将这些不同的数据取出。打印在控制台上。
    5,关闭资源。
代码:
	<span style="font-size:14px;">public static void main(String[] args) throws Exception
	{
		//1,创建udp socket,建立端点。
		DatagramSocket ds = new DatagramSocket(10000);
		//2,定义数据包。用于存储数据。
		byte[] buf = new byte[1024];
		DatagramPacket dp = new DatagramPacket(buf,buf.length);

		//3,通过服务的receive方法将收到数据存入数据包中。
		ds.receive(dp);//阻塞式方法。
		
		//4,通过数据包的方法获取其中的数据。
		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);
		//5,关闭资源
		ds.close();
	}</span>

练习:
编写一个聊天程序。
有收数据的部分,和发数据的部分。
这两部分需要同时执行。
那就需要用到多线程技术。
一个线程控制收,一个线程控制发。
因为收和发动作是不一致的,所以要定义两个run方法。
而且这两个方法要封装到不同的类中。
代码:
<span style="font-size:14px;">import java.io.*;
import java.net.*;
class Send implements Runnable
{
	private DatagramSocket ds;
	public Send(DatagramSocket ds)
	{
		this.ds = ds;
	}
	public void run()
	{
		try
		{
			BufferedReader 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.1.101"),10002);
				ds.send(dp);

				if("886".equals(line))
					break;
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("发送端失败");
		}
	}
}
class Rece implements Runnable
{
	private DatagramSocket ds;
	public 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());

				if("886".equals(data))
				{
					System.out.println(ip+"....离开聊天室");
					break;
				}
				System.out.println(ip+":"+data);
			}
		}
		catch (Exception e)
		{
			throw new RuntimeException("接收端失败");
		}
	}
}
class  ChatDemo
{
	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 Rece(receSocket)).start();
	}
}</span>

三、TCP传输
Tcp分客户端和服务端。

    客户端对应的对象是Socket。

    服务端对应的对象是ServerSocket。

客户端:
    通过查阅socket对象,发现在该对象建立时,就可以去连接指定主机。
    因为tcp是面向连接的。所以在建立socket服务时,
    就要有服务端存在,并连接成功。形成通路后,在该通道进行数据的传输。
  1、建立socket服务。指定要连接主机和端口。
  2、获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。
  3、获取socket流中的输入流,将服务端反馈的数据获取到,并打印。
  4、关闭客户端资源。
代码:
<span style="font-size:14px;">class TcpClient
{
	public static void main(String[] args)throws Exception 
	{
		Socket s = new Socket("192.168.1.254",10004);
		
		OutputStream out = s.getOutputStream();

		out.write("服务端,你好".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();
	}
}</span>

服务端:
    1、建立服务端的socket服务。ServerSocket();
    并监听一个端口。
    2、获取连接过来的客户端对象。
    通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。
    3、客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。
    并打印在控制台。
    4、获取接收到的客户端的socket流中的输出流,将反馈数据写入该流,通过网络反馈给客户端。
    5、关闭客户端连接资源。
代码:
<span style="font-size:14px;">class TcpServer
{
	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+"....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("哥们收到,你也好".getBytes());

		s.close();
	}
}</span>

练习:建立一个文本转换服务器
客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。
而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。
分析:
客户端:
既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。
源:键盘录入。
目的:网络设备,网络输出流。
而且操作的是文本数据。可以选择字符流。
步骤
1、建立服务。
2、获取键盘录入。
3、将数据发给服务端。
4、后去服务端返回的大写数据。
5、结束,关资源。
都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。

服务端:
源:socket读取流。
目的:socket输出流。
都是文本
代码:
<span style="font-size:14px;">import java.io.*;
import java.net.*;
class  TransClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.254",10005);

		//定义读取键盘数据的流对象。
		BufferedReader bufr = 
			new BufferedReader(new InputStreamReader(System.in));
		
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		//定义一个socket读取流,读取服务端返回的大写信息。
		BufferedReader bufIn = 
			new BufferedReader(new InputStreamReader(s.getInputStream()));

		String line = null;
		
		while((line=bufr.readLine())!=null)
		{
			if("over".equals(line))
				break;
			
			out.println(line);

			String str =bufIn.readLine();
			System.out.println("server:"+str);			
		}
		bufr.close();
		s.close();
	}
}
class  TransServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10005);

		Socket s = ss.accept();
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip+"....connected");
		//读取socket读取流中的数据。
		BufferedReader bufIn =
			new BufferedReader(new InputStreamReader(s.getInputStream()));

		//目的。socket输出流。将大写数据写入到socket输出流,并发送给客户端。
		PrintWriter out = new PrintWriter(s.getOutputStream(),true);
		String line = null;
		while((line=bufIn.readLine())!=null)
		{
			System.out.println(line);

			out.println(line.toUpperCase());
		}
		s.close();
		ss.close();
	}
}</span>

练习:
客户端通过键盘录入用户名。
服务端对这个用户名进行校验。
如果该用户存在,在服务端显示xxx,已登陆。
并在客户端显示 xxx,欢迎光临。
如果该用户不存在,在服务端显示xxx,尝试登陆。
并在客户端显示 xxx,该用户不存在。
每个用户最多登陆三次。
分析:
客户端定义每个用户只能登陆三次,三次失败自动退出
服务端设定用户的登陆尝试为三次,
登陆成功返回“欢迎光临”,三次失败之后自动断开客户端联系
服务端可以多用户同时登陆,需要将线程封装起来
步骤:
客户端:
1、建立服务端点。
2、读取客户端键盘录入。
3、通过socket 输出流将数据发给服务端。
4、读取服务端反馈信息。
5、关闭。
服务端:
1、建立服务端socket连接
2、将线程封装起来,实现多用户同时登陆
3、判断登陆信息并反馈相应的信息
4、关闭连接的客户端 资源。
代码:
<span style="font-size:14px;">import java.io.*;
import java.net.*;
class  LoginClient
{
	public static void main(String[] args) throws Exception
	{
		Socket s = new Socket("192.168.1.254",10008);

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

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

		BufferedReader bufIn =
			new BufferedReader(new InputStreamReader(s.getInputStream()));
		for(int x=0; x<3; x++)
		{
			String line = bufr.readLine();
			if(line==null)
				break;
			out.println(line);

			String info = bufIn.readLine();
			System.out.println("info:"+info);
			if(info.contains("欢迎"))
				break;
		}

		bufr.close();
		s.close();
	}
}
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+"....connected");
		try
		{
			for(int x=0; x<3; x++)
			{
				BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
				String name = bufIn.readLine();
				if(name==null)//如果名字为null,直接退出
					break;

				BufferedReader bufr = new BufferedReader(new FileReader("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)//用户名存在登陆成功
				{
					System.out.println(name+",已登录");
					out.println(name+",欢迎光临");
					break;
				}
				else
				{
					System.out.println(name+",尝试登录");
					out.println(name+",用户名不存在");
				}
			}
			s.close();
		}
		catch (Exception e)
		{
			throw new RuntimeException(ip+"校验失败");
		}
	}
}
class  LoginServer
{
	public static void main(String[] args) throws Exception
	{
		ServerSocket ss = new ServerSocket(10008);
		while(true)
		{
			Socket s = ss.accept();
			new Thread(new UserThread(s)).start();//多线程解决多用户同时登陆的问题
		}
	}
}</span><span style="font-size: 14px;">
</span>

练习:自定义图形界面浏览器、
分析:
模拟IE浏览器自定义浏览器,
该浏览器为客户端
要用到图形化界面的方法,做出图形界面
服务端返回的信息中包含响应头,
需要运用java提供的URL统一资源定位符将响应头拆解
使显示的返回信息只有响应主体。

URL方法:
int getDefaultPort() 
          获取与此 URL 关联协议的默认端口号。
 String getFile() 
          获取此 URL 的文件名。
 String getHost() 
          获取此 URL 的主机名(如果适用)。
 String getPath() 
          获取此 URL 的路径部分。
 int getPort() 
          获取此 URL 的端口号。
 String getProtocol() 
          获取此 URL 的协议名称。
 String getQuery() 
          获取此 URL 的查询部分。
openConnection() 
          返回一个 URLConnection 对象,它表示到 URL 所引用的远程对象的连接。
代码:
<span style="font-size:14px;">import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class  MyIEByGUI2
{
	private Frame f;
	private TextField tf;
	private Button but;
	private TextArea ta;
	
	private Dialog d;
	private Label lab;
	private Button okBut;
	MyIEByGUI2()
	{
		init();
	}
	public void init()
	{
		f = new Frame("my window");
		f.setBounds(300,100,600,500);
		f.setLayout(new FlowLayout());

		tf = new TextField(60);

		but = new Button("转到");

		ta = new TextArea(25,70);

		d = new Dialog(f,"提示信息-self",true);
		d.setBounds(400,200,240,150);
		d.setLayout(new FlowLayout());
		lab = new Label();
		okBut = new Button("确定");

		d.add(lab);
		d.add(okBut);

		f.add(tf);
		f.add(but);
		f.add(ta);
		myEvent();
		f.setVisible(true);
	}
	private void  myEvent()
	{
		okBut.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				d.setVisible(false);
			}
		});
		d.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				d.setVisible(false);
			}
		});
		tf.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				try
				{
						if(e.getKeyCode()==KeyEvent.VK_ENTER)
					showDir();
				}
				catch (Exception ex)
				{
				}
			}
		});


		but.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				try
				{
					showDir();
				}
				catch (Exception ex)
				{
				}								
			}
		});

		f.addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);	
			}
		});
	}
	private void showDir()throws Exception
	{

		ta.setText("");
		String urlPath = tf.getText();//http://192.168.1.254:8080/myweb/demo.html
		
		URL url = new URL(urlPath);

		URLConnection conn = url.openConnection();
		
		InputStream in = conn.getInputStream();

		byte[] buf = new byte[1024];

		int len = in.read(buf);

		ta.setText(new String(buf,0,len));
	}
	public static void main(String[] args) 
	{
		new MyIEByGUI2();
	}
}</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值