UDP协议
UDP(User Datagram Protocol)
-
用户数据报协议,面向无连接协议
-
不保证可靠的数据传输
-
速度快,可在较差网络下使用
-
计算机通讯:数据从一个IP的port出发,运输到另外一个IP的port上
-
UDP:无连接无状态的通讯协议
– 发送方发送消息,如果接收方刚好在目的地,就可以接受。如果不在,发送的消息就丢失了
– 发送方也无法得知是否消息发送成功
– UDP的好处就是简单,节省,经济
JAVA中实现UDP协议
DatagramSocket
类:通讯的数据管道
–send
和receive
方法(对于俩边来说是双向的)
–绑定一个IP和PortDatagramPacket
类
– 集装箱:封装数据
– 地址标签:目的地IP+Port- 注意
– 俩边没有主次之分
– 接收方必须早于发起方执行
//接收方
public class UdpRecv
{
public static void main(String[] args) throws Exception
{
DatagramSocket ds=new DatagramSocket(3000); //接收方的地址,3000端口
byte [] buf=new byte[1024];
DatagramPacket dp=new DatagramPacket(buf,1024);//封装
System.out.println("UdpRecv: 我在等待信息");
ds.receive(dp); //接收方在等待消息,一直是阻塞的,如果有消息,数据封装在dp中
System.out.println("UdpRecv: 我接收到信息");
String strRecv=new String(dp.getData(),0,dp.getLength()) +
" from " + dp.getAddress().getHostAddress()+":"+dp.getPort();
System.out.println(strRecv);
Thread.sleep(1000);
System.out.println("UdpRecv: 我要发送信息");
String str="hello world 222";
DatagramPacket dp2=new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("127.0.0.1"),dp.getPort());
ds.send(dp2);
System.out.println("UdpRecv: 我发送信息结束");
ds.close();
}
}
//发送方
public class UdpSend
{
public static void main(String [] args) throws Exception
{
DatagramSocket ds=new DatagramSocket();
String str="hello world";
DatagramPacket dp=new DatagramPacket(str.getBytes(),str.length(),
InetAddress.getByName("127.0.0.1"),3000);//集装箱的地址标签
System.out.println("UdpSend: 我要发送信息");
ds.send(dp);
System.out.println("UdpSend: 我发送信息结束");
Thread.sleep(1000);
byte [] buf=new byte[1024];
DatagramPacket dp2=new DatagramPacket(buf,1024);
System.out.println("UdpSend: 我在等待信息");
ds.receive(dp2);
System.out.println("UdpSend: 我接收到信息");
String str2=new String(dp2.getData(),0,dp2.getLength()) +
" from " + dp2.getAddress().getHostAddress()+":"+dp2.getPort();
System.out.println(str2);
ds.close();
}
}
//输出
UdpSend: 我要发送信息
UdpSend: 我发送信息结束
UdpSend: 我在等待信息
UdpSend: 我接收到信息
hello world 222 from 127.0.0.1:3000
UdpRecv: 我在等待信息
UdpRecv: 我接收到信息
hello world from 127.0.0.1:52724
UdpRecv: 我要发送信息
UdpRecv: 我发送信息结束
注意:接收方一定要先执行,让其一直等待着数据。不然发送方发送的数据会丢失
TCP协议
TCP:Transmission Control Protocol
- 传输控制协议,面向连接的协议
- 俩台机器的可靠无差错的数据传输
- 双向字节流传递(双方可同时发送数据)
JAVA 中TCP协议
服务器是实现一定的功能,必须在一个公开地址对外提供服务
TCP实现步骤:
- 服务器:创建一个
ServerSocket
,等待通讯 - 客户机:创建一个
Socket
,连接到服务器 - 服务器:
ServerSicket
接收到连接,创建一个Socket和客户的Socket建立一个专线连接,后续服务器和客户机的数据传输(一对Socket)会在一个**单独线程上(服务器建立)**运行 - 服务器的ServerSocket继续等待连接
实现类
-
ServerSocket
类:服务器码头
– 需要绑定IP+port -
Socket
:运输通道
– 客户端需要绑定服务器的IP和Port
– 客户端往Socket输入流中写入数据,送到服务端
– 客户端从Socket输出流取服务端过来的数据
– 服务端反之亦然 -
服务端等待响应时,处于阻塞状态
-
服务端可以同时响应多个客户端
-
服务端每接受一个客户端, 就启动一个独立的线程与之对应
-
客户端和服务端都可以选择关闭这个Socket通道
-
注意:服务端先启动,且一直保留。客户端后启动,可以先退出。
//客户端
public class TcpClient {
public static void main(String[] args) {
try {
Socket s = new Socket(InetAddress.getByName("127.0.0.1"), 8001); //需要服务端先开启
//同一个通道,服务端的输出流就是客户端的输入流;服务端的输入流就是客户端的输出流
InputStream ips = s.getInputStream(); //开启通道的输入流
BufferedReader brNet = new BufferedReader(new InputStreamReader(ips));
OutputStream ops = s.getOutputStream(); //开启通道的输出流
DataOutputStream dos = new DataOutputStream(ops);
//键盘的输入流
BufferedReader brKey = new BufferedReader(new InputStreamReader(System.in));
while (true)
{
String strWord = brKey.readLine();
if (strWord.equalsIgnoreCase("quit"))
{
break;
}
else
{
System.out.println("I want to send: " + strWord);
dos.writeBytes(strWord + System.getProperty("line.separator"));
System.out.println("Server said: " + brNet.readLine());
}
}
dos.close();
brNet.close();
brKey.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
//服务器
public class TcpServer2
{
public static void main(String [] args)
{
try
{
ServerSocket ss=new ServerSocket(8001);//驻守在8001端口
while(true)
{
Socket s=ss.accept(); //阻塞,等到有客户端连接上来
System.out.println("来了一个client");
new Thread(new Worker(s)).start();//创建独立线程,如果线程过多,服务器会崩。需要例如框架来创建线程
}
//ss.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
class Worker implements Runnable {
Socket s;
public Worker(Socket s) {
this.s = s;
}
public void run() {
try {
System.out.println("服务人员已经启动");
//定义输入流输出流
InputStream ips = s.getInputStream();
OutputStream ops = s.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(ips));
DataOutputStream dos = new DataOutputStream(ops);
while (true) {
String strWord = br.readLine();
System.out.println("client said:" + strWord +":" + strWord.length());
if (strWord.equalsIgnoreCase("quit"))
break;
String strEcho = strWord + " 666";
// dos.writeBytes(strWord +"---->"+ strEcho +"\r\n");
System.out.println("server said:" + strWord + "---->" + strEcho);
dos.writeBytes(strWord + "---->" + strEcho + System.getProperty("line.separator"));
}
br.close();
// 关闭包装类,会自动关闭包装类中所包装的底层类。所以不用调用ips.close()
dos.close();
s.close();
} catch (Exception e) {
e.printStackTrace();
}
}