android与PC之间的UDP通信
程序员文章站
2022-06-29 23:54:48
...
由于这段时间学习了安卓手机端与PC端之间的UDP通信原理,所以就在这里写一写自己的一些心得,我会尽量把自己遇到的难题以及自己的一些感觉写清楚,如果有写的不明朗的地方,还希望多多交流。
在铺上代码之前,我觉得很有将UDP通信的一些函数解释清楚,这样便于读者对之后代码的理解!
UDP和TCP/IP协议一样都是痛通信协议。下面我将简单介绍一下UDP和TCP/IP之间的异同点。
TCP(Transmission Control Protocol,传输控制协议)是面向连接的协议,也就是说在收发数据之间,双方必须建立可靠的连接,也就是行内术语“三次握手,四次挥手”这里就不作细述,网上有很多资料可查,读者有兴趣的话可以自己去看看。
UDP(User Data Protocol)UDP是一个非连接协议,传输数据之前,源端和终端之间是不建立连接的,简单的抓取来自应用程序的数据,并且将其扔到网络之上。
下面介绍实现安卓与PC之间通信需要的类,并对这些类的作用进行比较详细的叙述
DatagramSocket类:此类表示发送和接送数据的套接字(不明白可以直接跳过)
**简单解释一下DatagramSocket类的构造函数**
DatagramSocket()//构造数据报套接字并将其绑定到本地主机上任何可用的端口
Protected DatagramSocket (DatagramSocketImpl imp1)//创建带有指定DatagramSocketImpl的未绑定的数据报套接字
DatagramSocket(int port) //创建数据报套接字并将其绑定到本地主机绑定的端口号上
DatagramSocket(int port, InetAddress laddr)//创建数据报套接字并将其绑定到本地指定的IP地址和端口号
DatagramSocket(SocketAddress bindaddr) //创建数据报套接字,并将其绑定到本地指定的套接字地址
**DatagramPacket类的构造函数**
DatagramPacket(byte[] buf, int length) //构造DatagramPacket,并接收长度为length的数据包
DatagramPacket(byte[] buf, int lenght, InetAddress address int port) //将长度为length的数据包发送到主机上指定端口号
DatagramSocket(byte[] buf, int offset, int lenght, InetAddress address int port) // 构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int offset, int length) //构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) //构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int length, SocketAddress address) //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
**安卓端的源码**
public class MainActivity extends Activity {
***DatagramSocket socket;*** **//在收发信息的过程中只需要创建一个DatagramSocket对象即可**
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
socket = new DatagramSocket(9999);
} catch (SocketException e1) {
e1.printStackTrace();
}
Button btn = (Button) this.findViewById(R.id.sendBtn);
final EditText et = (EditText) this.findViewById(R.id.sendtext); // 为什么要添加final修饰
TextView tv = (TextView) this.findViewById(R.id.receivetext); // 获取文本框的内容
***// 发送信息的函数***
btn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
*new Thread(new Runnable() {
public void run() {* **//这里要说明一下在Android通信协议必须要放在线程里面进行**
String str = et.getText().toString();
Log.v("发送", str);
***sendMsg(str);*** //sendMsg函数已经封装好,这里直接拿来用
}
}).start();
}
});
**// 接收信息的函数**
try {
**receiveMsg(); //receiveMsg()函数也已经封装好,这里只需要拿来用即可,要体现java的封装思想**
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 定义发送消息的函数sendMsg()
*/
**public void sendMsg(String msg)** {
Log.v("v", "开始发送");
try {
**socket = new DatagramSocket(9999); //用DatagramSocket创建一个sokcet对象发送数据包,9999是本机的端口号
InetAddress server = InetAddress.getByName("192.168.31.207");
//上面代码的意思是获取本地主机的IP的地址,一般情况下使用InetAddress.getByName("IP")的形式,但是也可以用 getAllName()或者getLocalHost()的形式,得到本地主机的地址
byte data[] = msg.getBytes(); //将字符串转换成字节流,因为底层的传输都是字节传输
DatagramPacket pack = new DatagramPacket(data, data.length, server,
6024); // 创建DatagramPacket 对象数据包,这里的6024是我们要发送信息主机的端口号
socket.send(pack);**
Log.v("f", "发送成功!");
} catch (Exception e) {
Log.v("f", "发送失败!");
e.printStackTrace();
}
}
**public void receiveMsg() throws Exception** {
**// 创建线程,同理,接收信息也要放在线程里面接收**
new Thread(new Runnable() {
public void run() {
if (socket != null) {
try {
String str;
while (true) {
**// 创建一个空的字节数组
byte[] data = new byte[1024];
// 将字节数组和数组的长度传进DatagramPacket 创建的对象里面
DatagramPacket pack2 = new DatagramPacket(data,
data.length);**
Log.v("s", "pack2");
Log.v("s", "开始接收");
**socket.receive(pack2); // socket对象接收pack包,程序启动的时候,socket会一直处于阻塞状态,直到有信息传输进来**
String ip = pack2.getAddress().getHostAddress(); //这段代码的作用获取发送数据的IP地址
int port = pack2.getPort(); //获取发送数据端的端口号
System.out.println(ip);
System.out.println(port);
str = new String(pack2.getData(), 0, pack2.getLength()); // 将字节数组转化成字符串表现出来
Log.v("s", "接收成功: " + str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}
PC端代码
**public class UDPServe**r{
private SendandRecieveMsg srm;
public void UDPsetFrame(){
srm = new SendandRecieveMsg();
Frame frame = new Frame();
frame.setTitle("QQ"); //设置标题名
frame.setSize(800, 800); //设置窗体的大小
frame.setLayout(new FlowLayout()); //设置流式布局方式
frame.setLocationRelativeTo(null);
frame.setVisible(true); //设置可见
TextField tf = new TextField(20); //创建文本框, 20是指定的列数
Button senBtn = new Button("发送"); //设置发送按钮
TextArea ta = new TextArea(20,30);//创建文本域
frame.add(tf); //添加进frame窗体里面
frame.add(senBtn);
frame.add(ta);
ActionLis ml = new ActionLis(tf,srm); //将文本框里面内容传进去
senBtn.addActionListener(ml);//给发送按钮加上监听器
//关闭窗口调用的函数
frame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0); //这个函数的意思就是把整个窗体停用下来
}
});
while(true){
try {
**srm.UDPReceiveMsg(ta); //接收信息的socket不断接收信息,而且必须要放在最后,不断while会阻断其他程序的进行,UDPReceiveMsg()函数已经封装进SendandRecieveMsg类中**
} catch (SocketException e) {
e.printStackTrace();
}
}
}
public static void main(String[] arrys) throws IOException{
new UDPServer().UDPsetFrame(); //主函数,创建对象并启动
}
**public class ActionLis implements ActionListener**{
private TextField tf;
private SendandRecieveMsg srm;
//构造函数
public ActionLis() {
}
public ActionLis(TextField tf, SendandRecieveMsg srm) { //构造函数将文本tf和srm传进来
this.tf = tf;
this.srm = srm;
}
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equals("发送")){
srm.UDPSendMsg(tf.getText().trim()); //发送信息个Android端
System.out.println("发送的内容是:" + tf.getText().trim());
}
}
}
**public class SendandRecieveMsg**{
DatagramSocket socket; //定义DatagramSocket类对象
public SendandRecieveMsg(){
try {
**socket = new DatagramSocket(6024); //这里6024是我们PC的程序的端口号**
} catch (SocketException e) {
e.printStackTrace();
}
}
/**
* 定义发送信息函数
*/
**public void UDPSendMsg(String msg)**{
if(socket != null) {
try {
**InetAddress server = InetAddress.getByName("192.168.31.175");
byte data[] = msg.getBytes();
DatagramPacket pack = new DatagramPacket(data, data.length, server, 9999); //这是对方网络软件的端口
socket.send(pack); //这段代码在Android端已经介绍过,所以在这里就不再详述**
System.out.println("发送成功");
} catch (Exception e) {
System.out.println("发送失败");
e.printStackTrace();
}
}
}
/**
* 定义接收信息函数
*/
**public void UDPReceiveMsg(TextArea ta) throws SocketException**{
String str = null;
while(true) {
//创建字节数组
byte[] data = new byte[100];
//将字节数组和数组的长度传进DatagramPacket里面
DatagramPacket pack1 = new DatagramPacket(data, data.length);
try {
System.out.println("启动");
**//socket对象接收pack包
socket.receive(pack1);
String ip = pack1.getAddress().getHostAddress(); //获取IP地址
int port = pack1.getPort();//这段代码在Android端已经介绍过,所以在这里就不再详述**
str = new String(pack1.getData(), 0, pack1.getLength());
str = ip + ":" + port + ":" + str;
ta.insert(str, pos); //将消息插到文本里面
if(str.equals("bye")){
socket.close(); //关闭接口
}
} catch (Exception e) {
System.out.println("发生异常");
e.printStackTrace();
}
}
}
}
有什么不对的地方,希望读者可以提出意见,其实只要把了解UDP通信的原理,再将UDP通信的几个函数的用于弄清楚,就会对通信的底层原理理解的更加深刻。
上一篇: socket编程之bind()函数
下一篇: 怎么做企业网站seo推广?详细步骤