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

本文介绍了计算机网络通信的基本原理,包括OSI模型与TCP/IP模型,并深入探讨了Java中的网络编程技术,如使用InetAddress处理IP地址,UDP与TCP协议的应用及其实现方式。

------- android培训java培训、期待与您交流! ----------

1.网络通信原理

计算机之间的网络通信通常由最高的应用层向低打包封装到底层(最底层为物理设备),通过物理介质传递到另一台计算机上后再层层拆包,值到最高的应用层。

网络通信中的OSI模型与TCP/IP参考模型


数据在不同主机间的传输过程



2.InetAddress

IP地址是网络中设备的表示,在Java中,InetAdress用来描述并操作IP地址。

本机名:localhost(127.0.0.1)

端口号:除了不同的IP地址,在同一计算机中,不同的应用程序也要彼此区分开来,即产生了端口号,不同的软件(比如qq与飞信)使用不同的端口号,避免了彼此数据的错乱。

使用方法:

import java.net.*;
public class IPTest {
	public static void main(String[] args) {
		try {
			InetAddress ip=InetAddress.getLocalHost();//拿到本机IP
			System.out.println(ip.getHostName()+"@@@@"+ip.getHostAddress());//输出本机名称与ip地址
			InetAddress[] ipBaidu=InetAddress.getAllByName("www.baidu.com");//拿到所有的百度的ip
			for (InetAddress inetAddress : ipBaidu) {
				System.out.println(inetAddress);//输出
			}
		} catch (UnknownHostException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
}


3.UDP

封64k包,无连接,速度快。用于聊天,网游,视频等等对传输安全性不高但要求速度快的场景。
(相当于邮局)DatagramSocket接受和发送。 接收端要指定端口
(相当于包裹)DatagramPacket 发送的要指定发送地址与端口。

简单的发送接收例子:

简单发送端:

package com.cn.test;
import java.io.IOException;
import java.net.*;
public class UDPSend1 {
	public static void main(String[] args) throws IOException {
		System.out.println("发送端启动");
		DatagramSocket ds=new DatagramSocket();//发送端可以不指定端口号
		String str="fasongduan fasong";
		byte[] buf=str.getBytes();
		////DatagramPacket作为包裹,需要贴对方的ip号与端口号
		DatagramPacket dp=new DatagramPacket
				(buf, buf.length,InetAddress.getByName("192.168.1.4"),10000);
		ds.send(dp);
		ds.close();
	}
}

从键盘接受输入然后发送

package com.cn.test;
import java.io.*;
import java.net.*;
/**
 * 从键盘读取
 */
public class UDPSend2 {
	public static void main(String[] args) throws IOException {
		DatagramSocket ds=new DatagramSocket();//建立Socket
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//从键盘读取
		String line=null;
		while((line=br.readLine())!=null){
			byte [] buf=line.getBytes();
			DatagramPacket dp=new DatagramPacket
					(buf, buf.length,InetAddress.getByName("192.168.1.255"),10000);
			ds.send(dp);//发送
			if("886".equals(line))break;
		}
		ds.close();
	}
}


接收端:

package com.cn.test;

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

public class UDPRcv1 {
<span style="white-space:pre">	</span>public static void main(String[] args) throws IOException {
<span style="white-space:pre">		</span>System.out.println("接收端");
<span style="white-space:pre">		</span>DatagramSocket ds=new DatagramSocket(10000);//接收端要指定端口
<span style="white-space:pre">		</span>while(true){//循环监听
<span style="white-space:pre">			</span>byte[]buf=new byte[1024];
<span style="white-space:pre">			</span>DatagramPacket dp=new DatagramPacket(buf,buf.length);//接收的包裹
<span style="white-space:pre">			</span>ds.receive(dp);//邮局接收包裹
<span style="white-space:pre">			</span>String ip=dp.getAddress().getHostAddress();//获取包裹内的各个元素
<span style="white-space:pre">			</span>int pot=dp.getPort();
<span style="white-space:pre">			</span>String text=new String(dp.getData());
<span style="white-space:pre">			</span>System.out.println(ip+":"+pot+":"+text);
<span style="white-space:pre">		</span>}
<span style="white-space:pre">	</span>}
}

使用UDP的聊天程序,一个线程负责发送,一个线程负责接收。(将发送端的投递地址改为192.168.1.255)便可以广播。

package com.cn.test;
import java.io.*;
import java.net.*;

/**
 * UDP聊天程序,一个线程负责发送,一个线程负责接收
 */
class RcvThread implements Runnable{//负责接收的线程
	private DatagramSocket ds;
	public RcvThread (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 content=new String(dp.getData(),0,dp.getLength());//拆解包裹
				String ip=dp.getAddress().getHostAddress();
				int add=dp.getPort();
				System.out.println("内容"+content+"地址"+ip+"端口"+add);
			}
			
		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
	}
	
}
class SendThread implements Runnable{
	DatagramSocket ds;//Socket相当于邮局
	public SendThread(DatagramSocket ds){
		this.ds=ds;
	}
	public void run(){
		try {
			DatagramSocket ds=new DatagramSocket();
			BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
			String line=null;
			while((line=br.readLine())!=null){
				byte [] buf=line.getBytes();
				DatagramPacket dp=new DatagramPacket(buf, buf.length,InetAddress.getByName("192.168.1.4"),5244);
				ds.send(dp);//发送
				if("886".equals(line))break;
			}
			ds.close();
		} catch (Exception e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
}
public class UDPChater {
	public static void main(String[] args) throws SocketException {
		DatagramSocket rds=new DatagramSocket(5244);
		DatagramSocket sds=new DatagramSocket();
		//初始化赋值
		RcvThread rt=new RcvThread(rds);
		SendThread st=new SendThread(sds);
		//启动
		new Thread(rt).start();
		new Thread(st).start();
	}
}

4.TCP

相对于UDP,TCP需要与对方进行三次握手建立连接,形成通道(IO流)。而且,TCP通常采用Server(服务器)对应多个Client(客户端)的模式。


同UDP传输一样,TCP协议两端的设备仍靠Socket进行传输

下面是一个普通的字符串通过TCP协议传输的例子

客户端发送字符串

package com.cn.test;
import java.io.*;
import java.net.*;
public class TCPClientA {
	public static void main(String[] args) throws IOException {
		Socket sk=new Socket(InetAddress.getByName("192.168.1.4"), 5244);//客户端的Socket
		OutputStream os=sk.getOutputStream();//TCP的通道本质上就是IO流
		os.write("From kehuduan".getBytes());
		byte[] buf=new byte [1024];
		//接收返回
		InputStream is=sk.getInputStream();
		int len=0;
		while((len=is.read(buf))!=-1){
			System.out.println(new String(buf));
		}
		os.close();
		sk.close();
	}
}

服务端接收到以后返回信息

package com.cn.test;
import java.io.*;
import java.net.*;
public class TCPServer {
	public static void main(String[] args) throws Exception {
		ServerSocket ss=new ServerSocket(5244);//服务端的ServerSocket
		Socket s=ss.accept();//从ss得到Socket
		String ip=s.getInetAddress().getHostAddress();
		InputStream is=s.getInputStream();//读取流
		byte[] buf=new byte[1024];
		int len=is.read(buf);
		String text=new String(buf,0,len);
		System.out.println(ip+"@@"+text);
		OutputStream os=s.getOutputStream();//读取完以后返回信息
		Thread.sleep(5000);
		os.write("信息已经收到".getBytes());
		s.close();
		ss.close();
	}
}


既然TCP的通道是IO流,那就采用高效的IO流。

通过Buffered流与Print流实现的TCP传输

客户端

package com.cn.test;
import java.io.*;
import java.net.*;
/**
 * 客户端接收键盘录入发送到服务器端,服务器端返回给客户端大写字母
 */
public class TCPUpClient {
	public static void main(String[] args) throws Exception {
		Socket s=new Socket(InetAddress.getByName("192.168.1.4"),5245);//规定地址,端口
		BufferedReader br=new BufferedReader(new InputStreamReader(System.in));//键盘接收输入
		//从服务端接收的Reader
		BufferedReader brAfter=new BufferedReader(new InputStreamReader(s.getInputStream()));
		//发送的Writer
		PrintWriter pw=new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);
		String line=null;
		while((line=br.readLine())!=null){
			if("886".equals(line)){//终止条件
				break;
			}
			pw.println(line);
			String upReader=brAfter.readLine();
			System.out.println(upReader);
		}//发送完毕
		s.close();
//		
		
	}
}

服务端

package com.cn.test;
import java.net.*;
import java.io.*;
public class TCPUpServer {
	public static void main(String[] args) throws Exception{
		ServerSocket ss=new ServerSocket(5245);//设立端口
		Socket s=ss.accept();//拿到Socket
		//读取
		BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
		//写入输出流
		PrintWriter pw=new PrintWriter(new OutputStreamWriter(s.getOutputStream()),true);
		String line=null;
		while((line=br.readLine())!=null){
			String up=line.toUpperCase();
			pw.println(up);
		}
		s.close();
		ss.close();
	}
}

采取字符流上传txt文本文件到服务端,服务端接收成功后返回提示。

客户端

package com.cn.test2;
import java.io.*;
import java.net.*;
public class TCPUpFileClient {
	public static void main(String[] args) throws Exception {
		System.out.println("客户端开启……");
		Socket s=new Socket(InetAddress.getByName("192.168.1.4"),5246);
		BufferedReader br=new BufferedReader(new FileReader("ForTCP.txt"));
		PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
		String line=null;
		while((line=br.readLine())!=null){
			pw.println(line);
		}
		s.shutdownOutput();//------------------------表示关闭输出流
		BufferedReader brAfter=new BufferedReader(new InputStreamReader(s.getInputStream()));
		String str=brAfter.readLine();
		System.out.println(str);
		br.close();
		s.close();
	}
}

服务端

package com.cn.test2;
import java.io.*;
import java.net.*;
public class TCPFileServer {
	public static void main(String[] args) throws Exception {
		System.out.println("服务端开启……");
		ServerSocket ss=new ServerSocket(5246);
		Socket s=ss.accept();
		BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));//接收的
		PrintWriter pw=new PrintWriter(new FileWriter("TCPRcv.txt"),true);
		String line=null;

		while((line=br.readLine())!=null){
			pw.println(line);
		}
		//----------------------------------上传成功后给客户端一个提示
		PrintWriter pwAfter=new PrintWriter(s.getOutputStream(),true);
		pwAfter.println("上传完成");
		pw.close();
		s.close();
		ss.close();
	}
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值