【工具向】Android UDP與TCP工具類
來源:程序員人生 發布時間:2016-08-10 13:44:43 閱讀次數:2565次
甚么是UDP與TCP協議?
請看此篇文章
http://www.360doc.com/content/14/0325/09/1317564_363500997.shtml
簡單來講,他們都是兩種協議,UDP傳輸時候不需要建立連接,TCP需要建立連接,同時UDP使用了數據報情勢,而TCP使用流模式來進行傳輸,可靠性上TCP的可靠性遠大于UDP,UDP不能保證數據的正確性,有可能會出現丟包。
舉個例子:
用踢球來講,TCP就是1個人A踢出去另外一個人B接住了,然后另外一個人B又踢給了A;
而UDP來講就是1個人A,狠狠地往前開了1腳,然后另外一個人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)) != ⑴) {
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)) != ⑴) {
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連接時候不能像UDP1樣,可以隨時new,經過實戰項目發現,new屢次以后會使綁定的地址生成多個,所以必須使用單例模式來保證我們new的TCP類的唯1性,好了,我們來造1個輪子吧,空話少說直接上代碼:
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地址下載
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈