您的位置:首页 > 理论基础 > 计算机网络

【工具向】Android UDP与TCP工具类

2016-06-28 23:52 676 查看

什么是UDP与TCP协议?

请看此篇文章

http://www.360doc.com/content/14/0325/09/1317564_363500997.shtml

 

简单来说,他们都是两种协议,UDP传输时候不需要建立连接,TCP需要建立连接,同时UDP使用了数据报形式,而TCP使用流模式来进行传输,可靠性上TCP的可靠性远大于UDP,UDP不能保证数据的正确性,有可能会出现丢包。

 

举个例子:

用踢球来说,TCP就是一个人A踢出去另一个人B接住了,然后另一个人B又踢给了A;

而UDP来说就是一个人A,狠狠地往前开了一脚,然后另一个人B不知道会不会接到这个球。

 

UDP,TCP与socket是什么关系?

UDP与TCP是两种通信协议,而Socket是实现他们的API。

 

 

开始简单编程:

 

首先我们来看下java中的TCP和UDP吧:

 

1.使用TCP来进行网络通信

 

package tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

/**
*
* <pre>
* <p>TCPClient类</p>
*
* @author WindyStory
* =================================
* 	开发时间
* 		2016年6月28日下午10:12:57
* =================================
* </pre>
*/
public class TCPClient {
// 主机地址 127.0.0.1是本地的地址
public static final String HOST = "127.0.0.1";
// 主机的端口号 端口范围为1~65535,建议使用3000以上的
public static final int PORT = 23333;

/**
* TCP连接类
* @throws IOException
* @throws UnknownHostException
*/
public static void TCPConn() throws UnknownHostException, IOException{
//建立连接
Socket socket = new Socket(HOST,PORT);
//构造InputStream流进行读取
InputStream is = socket.getInputStream();
//构造OutputStream流进行写入数据
OutputStream os = socket.getOutputStream();

//写数据
os.write("Hello,I am Client!".getBytes());

//读取数据
int end = 0;
byte[] bs = new byte[1024];
while ((end = is.read(bs)) != -1) {
System.out.print(new String(bs).trim());//去掉空格
}

//使用完以后关闭流
os.close();
is.close();
socket.close();
}

public static void main(String[] args) {
try {
TCPConn();
} catch (IOException e) {
e.printStackTrace();
}
}
}


 

package tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
*
* <pre>
* <p>TCPServer类</p>
*
* @author WindyStory
* =================================
* 	开发时间
* 		2016年6月28日下午10:13:11
* =================================
* </pre>
*/
public class TCPServer {
// 主机的端口号 端口范围为1~65535,建议使用3000以上的
public static final int PORT = 23333;

/**
* TCP服务端类
*
* @throws Exception
*/
public static void TCPServerConn() throws Exception {
// 建立监听
ServerSocket serverSocket = new ServerSocket(PORT);
// 获取Socket对象
Socket socket = serverSocket.accept();
// 构造InputStream流进行读取
InputStream is = socket.getInputStream();
// 构造OutputStream流进行写入数据
OutputStream os = socket.getOutputStream();

// 写入
os.write("Hello,I am Server!".getBytes());
// 读取
int end = 0;
byte[] bs = new byte[1024];
while ((end = is.read(bs)) != -1) {
System.out.print(new String(bs).trim());// 去掉空格
}

// 关闭流
os.close();
is.close();
socket.close();
serverSocket.close();
}

public static void main(String[] args) {
try {
TCPServerConn();
} catch (Exception e) {
e.printStackTrace();
}
}
}


 

2.使用UDP来进行网络通信

 
package udp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
*
* <pre>
* <p>UDPClient类</p>
*
* @author WindyStory
* =================================
* 	开发时间
* 		2016年6月28日下午10:13:20
* =================================
* </pre>
*/
public class UDPClient {
// 主机地址 127.0.0.1是本地的地址
public static final String HOST = "127.0.0.1";
// 主机的端口号 端口范围为1~65535,建议使用3000以上的
public static final int PORT = 23333;

/**
* UDP连接类
*
* @throws IOException
* @throws UnknownHostException
*/
public static void UDPConn() throws UnknownHostException, IOException {
// 构造DatagramSocket
DatagramSocket socket = new DatagramSocket();

// 构造DatagramPacket
byte[] buf = "Hello,I am Client!".getBytes();
// 构造地址
InetAddress address = InetAddress.getByName(HOST);
// 构造发送的数据包
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, PORT);
// 发送数据
socket.send(packet);

// 读取数据
byte[] recBuf = new byte[1024];
// 构造接收的数据包
DatagramPacket recvPacket = new DatagramPacket(recBuf, recBuf.length);
// 接收的数据包
socket.receive(recvPacket);
// 接收的数据
System.out.println("Server:" + new String(recvPacket.getData(), 0, recvPacket.getLength()));

// 使用完以后关闭流
socket.close();
}

public static void main(String[] args) {
try {
UDPConn();
} catch (IOException e) {
e.printStackTrace();
}
}
}


package udp;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

/**
*
* <pre>
* <p>UDPServer类</p>
*
* @author WindyStory
* =================================
* 	开发时间
* 		2016年6月28日下午10:13:29
* =================================
* </pre>
*/
public class UDPServer {
// 主机的端口号 端口范围为1~65535,建议使用3000以上的
public static final int PORT = 23333;

/**
* TCP服务端类
*
* @throws Exception
*/
public static void UDPServerConn() throws Exception {
//接收的数据包
DatagramSocket server = new DatagramSocket(PORT);
byte[] recvBuf = new byte[1024];
//接收数据
DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
server.receive(recvPacket);

System.out.println("Client:" + new String(recvPacket.getData(), 0, recvPacket.getLength()));

//同客户端
int port = recvPacket.getPort();
InetAddress addr = recvPacket.getAddress();
String sendStr = "Hello ! I am Server";
byte[] sendBuf;
sendBuf = sendStr.getBytes();
DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, addr, port);
server.send(sendPacket);

//关闭流
server.close();
}

public static void main(String[] args) {
try {
UDPServerConn();
} catch (Exception e) {
e.printStackTrace();
}
}
}


在Android中使用TCP/UDP
 
在android中由于不能使用耗时操作在主UI线程中,所以我们需要使用AsyncTask类来开启异步线程执行网络请求,但是本人在实际项目中,高并发网络请求时,会出现AsyncTask失效的问题,这里建议使用开源的MultiAsynctask.
GitHub地址:
https://github.com/yanzhenjie/MultiAsynctask
 
UDP工具类可以使用改文章中的:
http://blog.csdn.net/qinpeng100423/article/details/8980423
这里贴下博主的代码,大家来看下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;

/**
* Copyright 2007 GuangZhou Cotel Co. Ltd.
* All right reserved.
* UTP服务类.
* @author QPING
*/
public class UdpServerSocket {
private byte[] buffer = new byte[1024];

private DatagramSocket ds = null;

private DatagramPacket packet = null;

private InetSocketAddress socketAddress = null;

private String orgIp;

/**
* 构造函数,绑定主机和端口.
* @param host 主机
* @param port 端口
* @throws Exception
*/
public UdpServerSocket(String host, int port) throws Exception {
socketAddress = new InetSocketAddress(host, port);
ds = new DatagramSocket(socketAddress);
System.out.println("服务端启动!");
}

public final String getOrgIp() {
return orgIp;
}

/**
* 设置超时时间,该方法必须在bind方法之后使用.
* @param timeout 超时时间
* @throws Exception
*/
public final void setSoTimeout(int timeout) throws Exception {
ds.setSoTimeout(timeout);
}

/**
* 获得超时时间.
* @return 返回超时时间.
* @throws Exception
*/
public final int getSoTimeout() throws Exception {
return ds.getSoTimeout();
}

/**
* 绑定监听地址和端口.
* @param host 主机IP
* @param port 端口
* @throws SocketException
*/
public final void bind(String host, int port) throws SocketException {
socketAddress = new InetSocketAddress(host, port);
ds = new DatagramSocket(socketAddress);
}

/**
* 接收数据包,该方法会造成线程阻塞.
* @return 返回接收的数据串信息
* @throws IOException
*/
public final String receive() throws IOException {
packet = new DatagramPacket(buffer, buffer.length);
ds.receive(packet);
orgIp = packet.getAddress().getHostAddress();
String info = new String(packet.getData(), 0, packet.getLength());
System.out.println("接收信息:" + info);
return info;
}

/**
* 将响应包发送给请求端.
* @param bytes 回应报文
* @throws IOException
*/
public final void response(String info) throws IOException {
System.out.println("客户端地址 : " + packet.getAddress().getHostAddress()
+ ",端口:" + packet.getPort());
DatagramPacket dp = new DatagramPacket(buffer, buffer.length, packet
.getAddress(), packet.getPort());
dp.setData(info.getBytes());
ds.send(dp);
}

/**
* 设置报文的缓冲长度.
* @param bufsize 缓冲长度
*/
public final void setLength(int bufsize) {
packet.setLength(bufsize);
}

/**
* 获得发送回应的IP地址.
* @return 返回回应的IP地址
*/
public final InetAddress getResponseAddress() {
return packet.getAddress();
}

/**
* 获得回应的主机的端口.
* @return 返回回应的主机的端口.
*/
public final int getResponsePort() {
return packet.getPort();
}

/**
* 关闭udp监听口.
*/
public final void close() {
try {
ds.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}

/**
* 测试方法.
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String serverHost = "127.0.0.1";
int serverPort = 3344;
UdpServerSocket udpServerSocket = new UdpServerSocket(serverHost, serverPort);
while (true) {
udpServerSocket.receive();
udpServerSocket.response("你好,sterning!");

}
}
}


 
可是博主没有写TCP的工具,TCP连接时候不能像UDP一样,可以随时new,经过实战项目发现,new多次以后会使绑定的地址生成多个,所以必须使用单例模式来保证我们new的TCP类的唯一性,好了,我们来造一个轮子吧,废话少说直接上代码:
 

package com.windystory.battlefield.net;

import android.util.Log;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class TCPUtils {
//端口号
public static final int PORT = 9090;
//地址
public static final String HOST = "192.168.0.100";
private byte[] buffer = new byte[1024];
public static Socket socket;

//Double CheckLock(DCL模式单例)
private static TCPUtils utils = null;

public  static TCPUtils getInstance() {
if (utils == null) {
synchronized(TCPUtils.class){
if (utils == null) {
utils = new TCPUtils();
}
}
}
return utils;
}

/**
* 构造函数,创建TCP客户端
*/
private TCPUtils() {
try {
socket = new Socket(HOST, PORT);
} catch (IOException e) {
e.printStackTrace();
}
}

/**
* 设置超时时间,该方法必须在bind方法之后使用.
*
* @param timeout 超时时间
* @throws Exception
*/
public void setSoTimeout(final int timeout) throws Exception {
socket.setSoTimeout(timeout);
}

/**
* 获得超时时间.
*
* @return 返回超时时间
* @throws Exception
*/
public int getSoTimeout() throws Exception {
return socket.getSoTimeout();
}

public final Socket getSocket() {
return socket;
}

/**
* 向指定的服务端发送数据信息.
*
* @param data 发送的数据信息
* @return 返回构造后俄数据报
* @throws IOException
*/
public final OutputStream send(
String data) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
OutputStream outputStream = socket.getOutputStream();
if (data != null) {
outputStream.write(data.getBytes());
}
return outputStream;
}

/**
* 接收从指定的服务端发回的数据.
*
* @return 返回从指定的服务端发回的数据.
* @throws Exception
*/
public final String receive()
throws Exception {
try {
InputStream inputStream = socket.getInputStream();
DataInputStream input = new DataInputStream(inputStream);
byte[] b = new byte[10000];
while (true) {
int length = input.read(b);
String Msg = new String(b, 0, length, "gb2312");
Log.v("data", Msg);
return Msg;
}
} catch (Exception ex) {
ex.printStackTrace();
}
return "";
}

/**
* 关闭tcp连接.
*/
public void close() {
try {
socket.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}


 使用时候可以使用如下代码:

new MultiAsynctask<Void, Void, Void>() {
@Override
public Void onTask(Void... voids) {
try {
TCPUtils.getInstance().send(".......");//发送
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}.execute();


 好了,就是这样,注意需要访问网络加入权限:

<uses-permission android:name=”android.permission.INTERNET”/>


Demo地址下载


Android学习交流群:523487222


(如果您觉得有用,欢迎加入,一起学习进步)
点击链接加入群【Android学习群】

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Android tcp udp