黑马程序员-java网络编程

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


一、网络编程概述:

1、网络模型

OSI参考模型与TCP/IP参考模型


2、网络通讯要素

1)IP地址

网络中设备的标识;

不易记忆,可用主机名;

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

InetAddress ia=InetAddress.getByName("www.baidu.com");
System.out.println(ia.getHostAddress());
System.out.println(ia.getHostName());
输出结果:

111.13.100.91
www.baidu.com

2)端口号

用于标识进程的逻辑地址;

端口的取值范围:0-65535。

常见的端口:网络服务(Web服务)为80;QQ聊天有两个端口,4000端口用于接收QQ状态信息的数据包,8080端口用于接收我们发送的聊天信息;FTP服务为21(20)。

3)传输协议

通讯规则。常见协议:TCP、UDP

UDP:

不需要建立连接;将数据及源和目的都封装在数据包中;每个数据包的大小限制在64K内;因为是无连接,所以是不可靠协议;也因此速度快。

TCP:

建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;也因此,效率稍低。


二、UDP传输

Socket:

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

例1:定义UDP发送端,将一段文字数据发送出去

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SendSocket {
	public static void main(String[] args)throws Exception{
		//通过DatagramSocket对象,创建UDP服务
		DatagramSocket ds=new DatagramSocket();
		//确定数据,并封装成数据包
		byte[] buf="udp chuan shu".getBytes();
		DatagramPacket dp=
				new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8080);
		//通过Socket的send方法,将已有的数据包发送出去
		ds.send(dp);
		//关闭资源
		ds.close();
	}
}

例2:定义UDP接收端,接收UDP协议传输的数据并处理

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class ReceiveSocket {

	public static void main(String[] args) throws Exception{
		//创建UDP socket,监听端点
		DatagramSocket ds=new DatagramSocket(8080);
		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);
		}
		//ds.close();
	}
}

例3:编写一个简易聊天程序

需求:有收数据部分与发数据部分,两部分需同时进行。因此需要多线程技术。

package com.cn.itcast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;

public class UDPChatTest {

	public static void main(String[] args) throws Exception{
		DatagramSocket sendSocket=new DatagramSocket();
		DatagramSocket receSocket=new DatagramSocket(8081);
		new Thread(new Send(sendSocket)).start();
		new Thread(new Receive(receSocket)).start();

	}
}
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){
				if("886".equals(line))      //当键盘录入"886"时,停止聊天
					break;
				byte[] buf=line.getBytes();
				DatagramPacket dp=
						new DatagramPacket(buf,buf.length,InetAddress.getByName("127.0.0.1"),8081);
				ds.send(dp);		
			}
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
class Receive implements Runnable{
	private DatagramSocket ds;
	public Receive(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 (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

三、TCP传输

通过Socket和ServerSocket建立客户端和服务器端。建立连接后,通过Socket中的IO流进行数据的传输。同样,客户端与服务器端是两个独立的应用程序。

例4:客户端向服务器端发送一个文本数据,服务器端接收数据后打印在控制台上

客户端:

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

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class TCPClient {

	public static void main(String[] args) {
		try {
			//创建客户端的socket,指定目的主机和端口
			Socket s=new Socket("127.0.0.1",8082);
			//获取socket中的输出流,用于发送数据
			OutputStream out=s.getOutputStream();
			out.write("TCP chuanshu".getBytes());
			s.close();
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}
服务器端:

package Com.cn.ItCast;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class TCPServer {

	public static void main(String[] args) {
		try {
			//建立服务端socket,并监听一个端口
			ServerSocket ss=new ServerSocket(8082);
			//通过accept方法获取连接过来的客户端对象
			Socket s=ss.accept();
			
			String ip=s.getInetAddress().getHostAddress();
			System.out.println(ip+"....isconnected");
			//获取客户端对象的读取流,用于读取客户端发送来的数据
			InputStream in=s.getInputStream();
			byte[] buf=new byte[1024];
			int len=in.read(buf);
			System.out.println(new String(buf,0,len));
			s.close();//关闭客户端
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

例5:建立一个文本转换服务器

需求:客户端给服务器端发送文本,服务器端会将文本转换成大写后返回给客户端。客户端可以不断地进行文本转换,直到客户端输入“over”时,转换结束。

客户端:

package com.cn.itcast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;

public class TransClient {

	public static void main(String[] args)throws Exception {
		Socket s=new Socket("127.0.0.1",8083);
		//建立读取流,读取键盘录入的数据
		BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
		//建立socket写入流,将读取到的键盘录入数据发送到服务器端
		BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		//建立socket读取流,读取从服务器端发来的转换后的文本数据
		BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
		
		String line=null;
		while((line=bufr.readLine())!=null){
			out.write(line);
			//必须加换行符,否则服务器端的readLine方法无法读到换行符,就不能返回数据
			out.newLine();
			out.flush();//刷新,将数据刷至服务器端
			//读取从服务器端发来的数据
			String str=in.readLine();
			System.out.println("server:"+str);
		}
		bufr.close();
		s.close();
	}

}
服务器端:

package com.cn.itcast;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class TransServer {

	public static void main(String[] args) throws Exception{
		ServerSocket ss=new ServerSocket(8083);
		Socket s=ss.accept();
		//建立socket读取流,读取从客户端发来的文本数据
		BufferedReader in=new BufferedReader(new InputStreamReader(s.getInputStream()));
		//建立socket写入流,将服务器端转换了的文本数据发送给客户端
		BufferedWriter out=new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		
		String line=null;
		//若客户端发送数据后不添上换行符,readLine方法将不断读取数据却不返回
		while((line=in.readLine())!=null){
			out.write(line.toUpperCase());
			out.newLine();
			out.flush();
		}
		s.close();
		ss.close();
	}

}
注意:服务器端与客户端的out对象若改为:PrintWriter pw=new PrintWriter(s.getOutputStream(),true);

这时,while循环里out的三句代码可简化为:pw.println(line.toUpperCase());


例6:客户端并发上传图片

客户端:

package com.cn.itcast;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public 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"))){   //确保文件格式为JPG
			System.out.println("图片格式错误!");
			return;
		}
		if(file.length()>1024*1024*5){            //确保文件大小不超过上限
			System.out.println("文件过大,超过上传上限!");
			return;
		}
		
		//建立各种流
		Socket s=new Socket("127.0.0.1",8085);
		FileInputStream fis=new FileInputStream(file);//获取本地文件读取流,用于读取本地图片
		OutputStream out=s.getOutputStream();//获取Socket的写入流,用于将图片数据发送给服务器端
		InputStream in=s.getInputStream();//获取Socket的读取流,用于读取服务器端返回的消息
		
		//读取本地图片并发送给服务器端
		byte[] buf=new byte[1024];
		int len=0;
		while((len=fis.read(buf))!=-1){
			out.write(buf,0,len);
		}
		s.shutdownOutput();//告诉服务器端数据已写完
		fis.close();
		
		//获取服务器端返回消息
		byte[] bufIn=new byte[1024];
		int num=in.read(bufIn);
		System.out.println(new String("服务器端返回消息:"+new String(bufIn,0,num)));
		
		s.close();
	}

}
服务器端:

package com.cn.itcast;

import java.net.ServerSocket;
import java.net.Socket;

public class PicServer {

	public static void main(String[] args) throws Exception{
		ServerSocket ss=new ServerSocket(8085);
		
		//并发处理各个客户端
		while(true){
			Socket s=ss.accept();
			new Thread(new PicThread(s)).start();//对于每个客户端,都建立相应的线程来处理
		}
	}

}
线程:

package com.cn.itcast;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


public class PicThread implements Runnable {
	private Socket s;
	PicThread(Socket s){
		this.s=s;
	}
	@Override
	public void run() {
		int count=1;
		String ip=s.getInetAddress().getHostAddress();//获取客户端IP地址
		System.out.println(ip+"...is connected");
		
		try {
			InputStream in=s.getInputStream();//创建Socket的读取流,用于读取客户端发来的数据
			//按"ip(n).jpg"格式创建不重名文件
			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();//创建Socket写入流,用于返回消息
			out.write((ip+":上传成功!").getBytes());
			fos.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}

例7:自定义图形化浏览器

/*
*例7:自定义图形化浏览器
*/
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
class GUIBrowser 
{
	public static void main(String[] args)throws Exception 
	{
		Frame f=new Frame("主窗体");
		    
		f.setBounds(500,400,300,200); 
		f.setLayout(new FlowLayout());

		Button b=new Button("转到按钮");
		final TextField tf=new TextField(60);
		final TextArea ta=new TextArea(25,70);

		f.add(b); 
		f.add(tf);
		f.add(ta);
	
		//窗体关闭
		f.addWindowListener(new WindowAdapter() 
		{
			public void windowClosing(WindowEvent e)
			{
				System.exit(0);
			}
		});
		//按下转到指定网页
		b.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent e)
			{
				//清屏
				ta.setText("");
				
				//通过获得的url地址,截取IP地址、端口及路径
				String urlPath=tf.getText();//http://192.168.1.101:11000
				int index=urlPath.indexOf("//")+2;
				String str=urlPath.substring(index);
				String[] arr=str.split(":");
				String IP=arr[0];
				int port=Integer.parseInt(arr[1]);
				
				try
				{
					//建立Socket及Socket的写入流,向服务器发送数据
					Socket s=new Socket(IP,port);
					PrintWriter out=new PrintWriter(s.getOutputStream(),true);
					
					//利用out向Tomcat服务器发送请求消息头
					out.println("GET /HTTP/1.1");
					out.println("Accept:*/*");
					out.println("Accept-Language:zh-cn");
					out.println("Host:192.168.1.101:11000");
					out.println("Connection:closed");
					out.println();//请求消息头与请求消息体的分隔空行
					
					//建立Socket的读取流,读取服务器返回的数据并显示在ta文本框内
					BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
					String line=null;
					while((line=bufr.readLine())!=null)
					{
						ta.append(line+"\r\n");
					}

					s.close();
				}
				catch (Exception ex)
				{
					System.out.println(ex.toString());
				}
			}
		});
		//按下回车键也转到指定网页
		tf.addKeyListener(new KeyAdapter()
		{
			public void keyPressed(KeyEvent e)
			{
				if(e.getKeyCode()==KeyEvent.VK_ENTER)
				{
					ta.setText("");
					
					String urlPath=tf.getText();
					int index=urlPath.indexOf("//")+2;
					String str=urlPath.substring(index);
					String[] arr=str.split(":");
					String IP=arr[0];
					int port=Integer.parseInt(arr[1]);
					
					try
					{
						Socket s=new Socket(IP,port);
						PrintWriter out=new PrintWriter(s.getOutputStream(),true);
						
						out.println("GET /HTTP/1.1");
						out.println("Accept:*/*");
						out.println("Accept-Language:zh-cn");
						out.println("Host:192.168.1.101:11000");
						out.println("Connection:closed");
						out.println();
						
						BufferedReader bufr=new BufferedReader(new InputStreamReader(s.getInputStream()));
						String line=null;
						while((line=bufr.readLine())!=null)
						{
							ta.append(line+"\r\n");
						}

						s.close();
					}
					catch (Exception ex)
					{
						System.out.println(ex.toString());
					}
				}
			}
		});

		f.setVisible(true);
	}
}

例8:URL

import java.net.URL;
class URLTest 
{
	public static void main(String[] args) throws Exception
	{
		//URL可以根据指定的协议、IP地址、端口号建立
		URL url=new URL("http://192.168.1.101:11000/mywbe/demo.html?name=haha&&age=30");

		//URL的几个重要get方法
		System.out.println("getFile():"+url.getFile());
		System.out.println("getHost():"+url.getHost());
		System.out.println("getPath():"+url.getPath());
		System.out.println("getPort():"+url.getPort());
		System.out.println("getProtocol():"+url.getProtocol());
		System.out.println("getQuery():"+url.getQuery());
	}
}
/*
 String getFile() 
          获取此 URL 的文件名。 
 String getHost() 
          获取此 URL 的主机名(如果适用)。 
 String getPath() 
          获取此 URL 的路径部分。 
 int getPort() 
          获取此 URL 的端口号。 
 String getProtocol() 
          获取此 URL 的协议名称。 
 String getQuery() 
          获取此 URL 的查询部分。 
*/

输出结果:

getFile():/mywbe/demo.html?name=haha&&age=30
getHost():192.168.1.101
getPath():/mywbe/demo.html
getPort():11000
getProtocol():http
getQuery():name=haha&&age=30

例9:URLConnection

import java.net.URL;

class URLConnectionTest 
{
	public static void main(String[] args) 
	{
		URL url=new URL("http://192.168.1.101:11000");
		URLConnection conn=url.openConnection();//通过该方法与服务器建立连接
		System.out.println(conn);

		InputStream in=conn.getInputStream();//获取读取流,读取从服务器发来的数据
		byte[] buf=new byte[1024];
		int len=0;
		System.out.println(new String(buf,0,len));
	}
}

四、DNS(Domain Name System)

DNA服务器,又叫域名解析服务器。

DNS功能:

每个IP地址都可以有一个主机名,主机名由一个或多个字符串组成,字符串之间用小数点隔开。有了主机名,就不用死记硬背每台IP设备的IP地址,只要记住相对直观有意义的主机名就行了。这就是DNS协议所要完成的功能。


主机名到IP地址的映射有两种方式:

1)静态映射,每台设备上都配置主机到IP地址的映射,各设备独立维护自己的映射表,而且只供本设备使用;
2)动态映射,建立一套域名解析系统(DNS),只在专门的DNS服务器上配置主机到IP地址的映射,网络上需要使用主机名通信的设备,首先需要到DNS服务器查询主机所对应的IP地址。

通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析)。设备支持在本地进行主机名解析,也支持通过DNS进行域名解析。在解析域名时,首先采用静态域名解析的方法,如果静态域名解析不成功,再采用动态域名解析的方法。可以将一些常用的域名放入静态域名解析表中,这样可以大大提高域名解析效率。



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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值