------- 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();
}
}
}
封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();
}
}