UDP
用户数据报协议(UDP,User Datagram Protocol)是一种无需建立连接就可以发送封装的 IP 数据包的方法。
特点:
(1)无连接
(2)开销小
(3)可多对多
连接方式:无连接,只负责发送
与TCP相比:
优点:
(1)传输效率高
(2)可一对多
缺点:
(1)不可靠
本次项目目标:采用UDP通信,测试手机与PC实时显示的延时。
PC(Java)Server端代码:
public class UDPServer implements Runnable {
private static final int PORT = 6000;
private byte[] msg = new byte[1024];
private boolean life = true;
public UDPServer() {
}
public boolean isLife() {
return life;
}
public void setLife(boolean life) {
this.life = life;
}
@Override
public void run() {
DatagramSocket dSocket = null;
DatagramPacket dPacket = new DatagramPacket(msg, msg.length);
try {
dSocket = new DatagramSocket(PORT);
while (life) {
try {
dSocket.receive(dPacket);
Log.i("msg sever received", new String(dPacket.getData()));
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (SocketException e) {
e.printStackTrace();
}
}
}
PC(C++)Server端代码:
#include <iostream>
#include <winsock2.h>
#include <stdio.h>
#include <sys/timeb.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")//连接库
#include <ctime>
#include <string>
#include <sstream>
#include <iomanip>
int main()
{//创建套接字,相当于句柄
WORD Version;
WSADATA wData;
Version = MAKEWORD(2, 2);
int n = WSAStartup(Version, &wData);
if (n != 0)//检查是否出错,不过一般不会出错的
{
cout << "Error!" << endl;
return -1;
}
SOCKET soc = socket(AF_INET, SOCK_DGRAM, 0);
if (INVALID_SOCKET == soc)
{
cout << "Error!" << endl;
return -1;
}
//创建端口
sockaddr_in addSer;
addSer.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addSer.sin_family = AF_INET;
addSer.sin_port = htons(6666); //端口随便,端口号的有效范围是从0到65535。
n = bind(soc, (sockaddr*)&addSer, sizeof(addSer)); //一般来说,大于49151的端口号都代表动态端口。绑定套接字
if (n == SOCKET_ERROR) //出错检查,出错,可能端口被占用了,需要换一个
{
cout << "Error!" << endl;
return -1;
}
char Send[256]; //发送字符串
char Rev[256]; //接收字符串
long Time1;
long Time2;
sockaddr_in addClient; //接收方的地址信息结构体
int len = sizeof(sockaddr);
struct timeb t;
while (1)
{
int i = recvfrom(soc, Rev, 256, 0, (sockaddr*)&addClient, &len); //接受,阻塞在这,直到接收到信息
Rev[i] = '\0';
if (Rev[0] == 'Q')
{
cout << "Char end!" << endl;
break;
}
cout << inet_ntoa(addClient.sin_addr) << " say :" << Rev << endl; //输出发送方的IP,和信息
ftime(&t);
Time1 = t.time;
Time2 = t.millitm;
cout << Time1 << "." << Time2 << endl;
//sendto(soc, Time, strlen(Time), 0, (sockaddr *)&addClient, len); //发送消息
}
closesocket(soc); //关闭套接字
WSACleanup();
return 0;
}
Android端(Java)代码:
AndroidManifest.xml中增加权限:
<uses-permission android:name="android.permission.INTERNET" />
mainactivity主程序代码:
package com.example.udp;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.input);
btn = (Button) findViewById(R.id.btn_send);
System.out.println("启动");
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread(sendMyMessage).start();//新线程,防止堵塞主线程
}
});
}
private DatagramSocket socket;
private DatagramPacket packet;
private final String IP = "192.168.43.107";
private final int ServerPORT = 6666;
private final int ClientPORT = 6666;
private EditText et;
private Button btn;
String Time;
Runnable sendMyMessage = new Runnable() {
@Override
public void run() {
try {
socket = new DatagramSocket(ClientPORT);//本地发送窗口
//InetAddress serverIP=InetAddress.getByName(IP);
Time = Long.toString(System.currentTimeMillis());
packet = new DatagramPacket(Time.getBytes(), Time.getBytes().length, InetAddress.getByName(IP), ServerPORT);//数据打包,服务器地址和接收窗口
socket.send(packet);//发送消息
/*接受服务器回传消息
packet = new DatagramPacket(buf,buf.length);
socket.receive(packet);*/
socket.close();//发送完就可以关闭了,防止端口占用
} catch (Exception e) {
e.printStackTrace();
}
}
};
}
Layout代码:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:hint="请输入发送的信息"
android:id="@+id/input"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:id="@+id/btn_send"
android:layout_marginTop="10dp"
android:text="send"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/receive"
android:text="收到信息为: "
/>
</LinearLayout>
多次测试延时在100ms内,低延时,符合实时性,后续将基于udp探索实时传输视频的通信方案。