UDP编程
UDP是无连接的网络,不需要确定接收方是否收到。
不需要建立连接通道的
数据大小有限制
不可靠连接
执行效率高
发送方代码:
package day20T.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Send {
public static void main(String[] args) throws IOException {
//创捷套接字对象
DatagramSocket ds = new DatagramSocket() ;
//创建发送的包
byte[] bys = "Hello UDP".getBytes() ;
int length = bys.length ;
InetAddress address = InetAddress.getByName("192.168.43.194") ;//这个地址是接收方的地址,根据实际情况设定
int port = 10088 ; //完成UDP数据收发需要的条件:①发送方知道接收方的IP地址 ②发送方与接收方具有相同的接口
/**
* DatagramPacket(byte[] buf, int length, InetAddress address, int port)
* 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
*/
DatagramPacket dp = new DatagramPacket(bys, length, address, port) ;
ds.send(dp);
ds.close();
}
}
接收方代码:
package day20T.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Receive {
public static void main(String[] args) throws IOException {
// InetAddress address = InetAddress.getByName("malaganguo") ;
//创建套接字对象
DatagramSocket ds = new DatagramSocket(10088) ;
byte[] bys = new byte[1024] ;
int length = bys.length;
//创建接收包对象
DatagramPacket dp = new DatagramPacket(bys, length);
//接受
ds.receive(dp);
//获取地址
InetAddress addr = dp.getAddress() ;
//将InetAddress转换对象addr转为字符串hostAddr
String hostAddr = addr.getHostAddress();
int len2 = hostAddr.length() ;
String data = new String(bys, 0, len2) ;
System.out.println("当前接受的数据来自" + hostAddr +"是" + data);
}
}
TCP编程
TCP协议是面向连接的协议,创建连接时需要进行著名的“3次握手”,断开连接时需要进行著名的“4次挥手”。不过在JAVA中,我们在TCP编程中并不需要手动配置这些东西,java将通信链路的建立和拆除封装成了不同的类,我们面向对象编程中只需要负责调用这些类就就可以了。
TCP编程的设计思路
与UDP编程不同,TCP编程是客户机(Client)和服务器(Server)之间的通信,服务器起到转发的功能,负责为客户机提供服务。
客户端编程:
①客户端将自己的文件或者消息发送给服务器之前需要先建立连接。所以需要先创建套接字对象来绑定服务器的IP地址并约定端口号。
Socket s = new Socket("这里是地址",这里是端口号(0~65535)) ;//如果是我们自己定义的端口,那么不要用小于1024的!
②如果传输的是文件那么需要创建字符缓冲对象来读取文件: BufferedReader br = new BufferedReader(new FileReader("文件的路径名称")) ;
如果传输的是我们键盘录入的信息的话,需要创建缓冲区的键盘录入: BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
③创建通道的对象: BufferedWriter br = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;
④一边从br中读取字符流,一边往通道中写入:
String line = null ;
while((line=br.readLine()) != null){
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
⑤发送完毕后关闭输出的套接字对象停止发送: s.shutdownOutput() ;
⑥如果服务器对客户机发送的数据收到后对客户机有反馈的话,接受这个反馈。创建字符读缓冲区接受来自信道的数据:
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())) ;
假设只有一行数据,接受: String Client = br.readLine() ;
在控制台上打印出来:System.out.println(Client) ;
关闭资源:通道是没有关闭的bw
br.close() ;
s.close();
一个客户端的Demo:
package day21.TCPupload;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class UploadClient {
public static void main(String[] args) throws IOException {
//创建套接字对象
Socket s = new Socket("127.0.0.1" ,12345) ;
//创建字符缓冲区读取文件
BufferedReader br = new BufferedReader(new FileReader("UserDao.java")) ;
//创建通道
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())) ;
//将读取到的内容写入通道中
String line = null ;
while((line=br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列。如果在shutdown后还有发送数据,那么抛出 IOException
s.shutdownOutput();
//接收来自服务器的反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream())) ;
String client = brClient.readLine() ;
System.out.println(client);
//关闭资源
br.close();
s.close();
}
}
服务器端编程:
在TCP创建连接发送数据中,服务器端需要创建的套接字为服务器套接字(不同于UDP,因为是面向连接)。
①创建服务器端套接字: ServerSocket ss = new ServerSocket("这里的端口号需要与客户端约定一致") ;
②调用ServerSocket对象的accept()方法,这个方法为对信道的监听器,监听信道中是否有信息,如果有信息,以Socket的类型捕获这个信息到对象中: Socket accept = ss.accpet() ;
③创建读缓冲区的对象,这个缓冲区中用来读取来自监听器得到的输入流,得到监听器中的输入流可以使用监听器对象调用getInputStream()方法: BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())) ;
④创建缓冲区字符输出流对象,用来接受监听器从信道中获取的数据:BufferedWriter bw = new BufferedWriter(new FileReader("这里是一个存储的文件")) ;
⑤ 从监听器中一边读出,一边写入服务器端文件中:
String line = null ;
while((line=br.readLine()) != null){
bw.write(line) ;
bw.newLine() ;
bw.flush() ;
}
⑥ 反馈,告诉客户机这里已经成功接收到了数据:
1)创建缓冲区字符输出流,这个流向监听器中写入数据,用来发送给客户端: BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream())) ;
2)向流中写入数据:
bw.write("这里写想要反馈的东西") ;
bw.newLine() ;
bw.flush() ;
⑦关闭资源:accept.close() ;
bw.close() ;
总结
TCP/UDP两个协议在JAVA中编程不仅可以传输手动输入的数据,还可以传输文本文件,图片,音乐等等等等。但是要注意:不仅仅是字符流,在使用字节流缓冲传送图片等资源的时候,也需要调用flush()这个方法,否则可能会出现最后一个缓冲区中的数据接收不到,造成图片等的部分却失。
TCP/UDP在上面的两个例子中都是在各自的main线程中执行定义的,所以只能是单工的,我们可以创建两条线程,分别实现发送和接受的功能,那么就可以实现双工,接近于聊天室。