顯示具有 UDP 標籤的文章。 顯示所有文章
顯示具有 UDP 標籤的文章。 顯示所有文章

2015年4月29日 星期三

[iOS] Tab Bar分頁+UDP通訊

不知道怎樣寫分頁或是怎樣做UDP通訊嗎??

最近好不容易弄出了一點樣子,把它記錄起來,以免以後忘記.

首先分頁是使用tab bar元件-GG Tab Bar(https://github.com/Goles/GGTabBar)

,讓分頁切成四塊(同時建立四個.h+.m+.xib檔案)

可以看到有分了Page1,2,3,4分頁,以及對應的xib檔


首先,先在各個page.m裡面新增:


- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.tabBarItem = [[UITabBarItem alloc] initWithTitle:nil
                                                        image:[UIImage imageNamed:@"user_normal"]
                                                selectedImage:[UIImage imageNamed:@"user_pressed"]];
    }
    return self;
}

(image的部份就是要自己找圖或是下載source code,名稱自行調整,但需要對應到Images.xcassets裡面的檔案名稱)


step2: AppDelegate.h+m的部份

AppDelegate.h

#import <UIKit/UIKit.h>

#import "AsyncUdpSocket.h"
#define global ((AppDelegate *)[[UIApplication sharedApplication] delegate])

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    AsyncUdpSocket *udpSocket;
    NSTimer *timer;
    long tag;
}
@property (strong, nonatomic) UIWindow *window;
@property (nonatomic,retain) NSMutableArray *globalData;


@end


AppDelegate.m


#import "AppDelegate.h"
#import "GGTabBarController.h"
#import "Page1.h"
#import "Page2.h"
#import "Page3.h"
#import "Page4.h"


@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    
    NSLog(@"open");
    
    global.globalData = [[NSMutableArray alloc] initWithCapacity:300];
    
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    [udpSocket bindToPort:2601 error:&error]; //綁定一個port 讓發送的source port / 指定接收的port 都是這一個
    [udpSocket receiveWithTimeout:-1 tag:0];//Start listening for a UDP packet.
    timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(sender) userInfo:nil repeats:YES];
    
    GGTabBarController *tabBar = [[GGTabBarController alloc] init];
    
    Page1 *vc1 = [[Page1 alloc] init];
    Page2 *vc2 = [[Page2 alloc] init];
    Page3 *vc3 = [[Page3 alloc] init];
    Page4 *vc4 = [[Page4 alloc] init];
    
    tabBar.viewControllers = @[vc1, vc2, vc3, vc4];
    self.window.rootViewController = tabBar;
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

//Server端 接收
-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    //NSLog(@"in server");
    Byte *convert_to_byte = (Byte *)[data bytes];
    int length = data.length;
    //NSLog(@"length = %d",length);
    int receive[length];
    NSNumber *number;
    NSMutableArray *intArray = [[NSMutableArray alloc] init];
    
    for (int i = 0 ; i < [data length]; i++) {
        //printf("conver to byte = %d\n",convert_to_byte[i]);
        int combine = (int)convert_to_byte[i];
        //NSLog(@"%ld",combine);
        receive[i] = combine;
        number =[NSNumber numberWithInt:combine];
        [intArray addObject:number];
        NSLog(@"number =%@",number);
        //[global.globalData addObject:number];
        //NSLog(@"i=%@",global.globalData[i]);
        
        NSLog(@"%d",receive[i]);//詳細接收
    }
    [global.globalData setArray:intArray];
    [intArray removeAllObjects];
    
    for(int i = 0; i < global.globalData.count; i++){
        NSLog(@"i=%@",[global.globalData objectAtIndex:i]);
    }
    
    NSLog(@"global-data count= %lu",(unsigned long)global.globalData.count);
    
    //receive要解析,
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}


-(void) sender{
    //NSLog(@"timer");
    const unsigned char byte[] = {80,67,77,71,1,69,78,68};
    NSData *data = [NSData dataWithBytes:byte length:sizeof(byte)];
    [udpSocket sendData:data toHost:@"210.202.53.147" port:2601 withTimeout:-1 tag:tag];
}

@end

step3 : 建立udp通訊

這部份在前幾篇有講到附上網址:udp通訊part

(不過這部份已經有寫在上面了)



做完通訊,又有tab bar分頁功能以後,就是把分頁內容建立好囉!

教學到此結束,end.


2015年3月13日 星期五

[iOS] UDP Socket 實作-含程式碼 / 完整範例 / Youtube 實測

終於可以把udp socket 做出來了!

每次google 都是那幾篇.....而且每個都寫很不完整(很多都抄同一篇的)

搞了半天什麼CocoaAsyncSocket , GCDAsyncSocket , BSD Socket.....

沒有一篇寫比較完整,後來還好在github上有一個可以用的(不過是for Mac ,not for

iphone) 於是就仿照著寫了以後就可以用了!

--------------------------------------------------------------------------------------------------------------------------

(正文開始)

要寫socket 一定是要分兩部分 server & client , 然後在眾多的library裡面我選擇是:

AsyncUdpSocket

首先,先開一個project,然後add files to (project name)...

把AsyncUdpSocket.h / AsyncUdpSocket.m 加入(放哪邊不重要,不影響)




然後我們需要先到ViewController.h / Main.storyboard來宣告/拉一些物件


這邊(server)會需要一個輸入port 的textfield,一個按鈕 以及一個textview

別忘記要把他們兩邊做連結!


ViewControlloer.h:

//
//  ViewController.h
//  UdpServer
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015年 daniel. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AsyncUdpSocket.h"

@interface ViewController : UIViewController
{
    AsyncUdpSocket *udpSocket;

}

@property (weak, nonatomic) IBOutlet UITextField *port;
@property (weak, nonatomic) IBOutlet UIButton *start;
@property (weak, nonatomic) IBOutlet UITextView *textview;

- (IBAction)startButton:(id)sender;


@end


接下來就是

ViewController.m:

//
//  ViewController.m
//  UdpServer
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015年 daniel. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize port;
@synthesize start;
@synthesize textview;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];//初始化
    
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)startButton:(id)sender {
        //start udp server
        NSLog(@"Socket open");
        int port_int = [port.text intValue];
        if(port_int < 0 || port_int > 65535)
        {
            port_int = 0;
        }
        
        NSError *error = nil;
        
        if (![udpSocket bindToPort:port_int error:&error]) {
            return;
        }
        
        [udpSocket receiveWithTimeout:-1 tag:0];
        [port setEnabled:NO];
}

-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if(msg)
    {
        //textview.text  msg;
        NSLog(@"message is %@",msg);
        
        //以下這串是為了讓他能夠顯示在畫面上
        NSString *temp = [NSString stringWithFormat:@"%@\n",msg];
        NSMutableDictionary *attribute = [NSMutableDictionary dictionaryWithCapacity:1];
        NSAttributedString *as = [[NSAttributedString alloc] initWithString:temp attributes:attribute];
        //使用append的方式 ,但是他是NSAttributedString格式 所以才要先轉換,不能直接使用NSString!
        [[textview textStorage] appendAttributedString:as];
    }
    else
    {
        NSLog(@"converting UTF-8 Error");
    }
    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}
@end


在viewDidLoad這邊就是app一開始會跑的地方,當然是把socket初始化

然後在button按下去觸發的這個函式(IBAction)startButton:(id)sender )

我們需要把使用者輸入的port 放進int port_int裡面

然後如果使用者輸入數字超過0~65535這個區間 就直接給他port = 0

接著在-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port

這一段,我們必須要先宣告一個NSData來接收資料(data),編碼這邊使用UTF-8

如果msg有東西則顯示在螢幕上

記得最後面要加

    [udpSocket sendData:data toHost:host port:port withTimeout:-1 tag:0];

    [udpSocket receiveWithTimeout:-1 tag:0];

不然只能接收一次 !



--------------------------------------------------------------------------------------------------------------------------

然後就是 Client端了


一樣是把兩邊做連結(別忘了要import "AsyncUdpSocket.h")


//
//  ViewController.m
//  UdpClient
//
//  Created by daniel on 2015/3/13.
//  Copyright (c) 2015年 daniel. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

@synthesize addr;
@synthesize port;
@synthesize msg;
@synthesize sendButton;
@synthesize logView;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    udpSocket = [[AsyncUdpSocket alloc] initWithDelegate:self];
    NSError *error = nil;
    
    if(![udpSocket bindToPort:0 error:&error])
    {
        NSLog(@"Error binding: %@",error);
        return;
    }
    
    [udpSocket receiveWithTimeout:-1 tag:0];
    
    NSLog(@"Ready");
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(IBAction)send:(id)sender
{
    NSString *host = [addr text];
    NSLog(@"Address: %@",host);
    
    
    int port_int = [[port text] integerValue];//跟原本的不太一樣
    if(port_int <=0 || port > 65535)
    {
        NSLog(@"Valid port require");
    }
    
    NSString *message = [msg text];
    if (message.length == 0) {
        NSLog(@"Message require");
    }
    
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    
    if(data != nil)
        NSLog(@"data = %@",data);
    
    [udpSocket sendData:data toHost:host port:5000 withTimeout:-1 tag:tag];
}


-(void) onUdpSocket:(AsyncUdpSocket *)sock didSendDataWithTag:(long)tag
{
    //you could add checks here
}

- (void)onUdpSocket:(AsyncUdpSocket *)sock didNotSendDataWithTag:(long)tag dueToError:(NSError *)error
{
    // You could add checks here
}

-(BOOL) onUdpSocket:(AsyncUdpSocket *)sock didReceiveData:(NSData *)data withTag:(long)tag fromHost:(NSString *)host port:(UInt16)port
{
    
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if(msg)
    {
        NSLog(@"Receive: %@",msg);
    }
    else
    {
        NSLog(@"Receive Unknown message from %@:%hu",host,port);
    }
    [udpSocket receiveWithTimeout:-1 tag:0];
    return YES;
}

@end

在viewDidLoad這邊一樣要先初始化udpSocket,然後在sendbutton觸發這個action的

event這邊:
-(IBAction)send:(id)sender
{
    NSString *host = [addr text];
    把使用者輸入的ip放入host變數   

    NSLog(@"Address: %@",host);
    
    
    int port_int = [port text];
    
    把使用者輸入的port放進去port_int變數   

    if(port_int <=0 || port > 65535)
    {
        NSLog(@"Valid port require");
    }
    
    NSString *message = [msg text];

    把使用者輸入的message放進去message變數

    if (message.length == 0) {
        NSLog(@"Message require");
    }
    
    NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
    
   把要傳出去的message轉換為NSData型態,編碼使用utf-8

    if(data != nil)
        NSLog(@"data = %@",data);
    
    [udpSocket sendData:data toHost:host port:5000 withTimeout:-1 tag:tag];
    
    這邊為了測試方便直接把port 寫死5000,其實應該要寫port:port_int才對
}


好了!

這樣server / client 都有了 就可以開始通訊拉!




附上程式碼!


https://www.youtube.com/watch?v=wNX29RxA2K8&feature=youtu.be
https://www.youtube.com/watch?v=mDJv2UHnyZg&feature=youtu.be
附上實測證明可以用

2014年8月12日 星期二

[Android] UDP Receive / Send 完整-可執行-附檔案-教學

花了兩三個禮拜終於把Android UDP搞定!

首先,要先搞懂Thread / Handler是甚麼,不然這篇往下看沒有意義(因為會看不懂)

在MainActivity的部分,這邊負責主要的UI介面+Handler+Thread呼叫

package com.example.thread_example;

import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

import android.annotation.SuppressLint;
import android.net.wifi.WifiInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.StrictMode;
import android.support.v7.app.ActionBarActivity;
import android.text.format.Time;
import android.util.Log;
import android.widget.TextView;

@SuppressLint("NewApi")
public class MainActivity extends ActionBarActivity {

public static Handler exHandler;
private TextView txv;
private ChatServer chatserver;
private ChatSender chatsender;
public static InetAddress IP;
public WifiInfo mwifiInfo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (android.os.Build.VERSION.SDK_INT > 9) {
   StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
   StrictMode.setThreadPolicy(policy);
}

txv = (TextView) findViewById(R.id.textView);
//利用handler來顯示接收到的文字
exHandler=new Handler() {
       @Override
       public void handleMessage(Message msg) {
        super.handleMessage(msg);
        String msgString = (String)msg.obj;
        Log.d("Handler","Now in Handler");
        txv.setText(null);
        txv.setText(msgString+"\n"+txv.getText().toString());
       }
   };
        //獲得Wifi的內部網路IP
   StringBuilder IFCONFIG=new StringBuilder();
   try {
       for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
           NetworkInterface intf = en.nextElement();
           for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
               InetAddress inetAddress = enumIpAddr.nextElement();
               if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress() && inetAddress.isSiteLocalAddress()) {
               IFCONFIG.append(inetAddress.getHostAddress().toString()+"\n");              
               }
           }
       }
       txv.setText(IFCONFIG.toString());
       Log.d("LOG_Text", IFCONFIG.toString());
   } catch (SocketException ex) {
       Log.e("LOG_TAG", ex.toString());
   }


try{
chatserver = new ChatServer();
chatserver.start();
chatsender = new ChatSender();
chatsender.start();
Log.d("User","Thread start...");

}catch(Exception e)
{
String str = e.toString();
Log.e("Error by User", str);
}

}

protected void onPause(){
super.onPause();
if(chatserver != null)
{
if(!chatserver.isInterrupted())
{
chatserver.interrupt();
}
}
}

}

有一點長,這邊元件只有拉一個TextView而已,十分簡單。

IFCONFIG 

這邊負責顯示WIFI的IP

Thread--chatserver/chatsender

則是另外開兩個java檔(與mainActivity.java同層)分別做為接收與傳送,.start()就是讓他啟動而已。

exHandler

這邊負責顯示接收到的資訊(不能用static來傳值,因為Android不支援,至於為什麼我也不清楚),並把他印出來在textview上面。



Receiver部分(chatserver.java)

package com.example.thread_example;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

import android.os.Bundle;
import android.os.Message;
import android.util.Log;

public class ChatServer extends Thread{
private DatagramSocket server = null;
private static final int PORT = 8000;
public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
public void run(){

byte[] byte1024 = new byte[1024];
//Message msg = new Message();
//Bundle data = new Bundle();
DatagramPacket dPacket = new DatagramPacket(byte1024, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
while(true)
{
//印出來到螢幕上
txt = new String(byte1024, 0, dPacket.getLength());
MainActivity.exHandler.sendMessage(MainActivity.exHandler.obtainMessage(1,txt));
Log.d("User","Handler send Message");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
private void CloseSocket(DatagramSocket socket) throws IOException{
socket.close();
}
}

這邊宣告一個1024的byte來接收資料(按照你的資料量大小來調整宣告大小)

一定要宣告datagramSocket,datagramPacket,一個是連線,一個是接收封包用,至於handler這邊的

sendMessage就是回傳到MainActivity來讓textview顯示接收的資訊而已。結構上有兩個while(),第

一個while會卡在receive()這邊,一直到有封包進來才會往下跑到第二個while(),第二個則是印出資

訊,沒有甚麼特別的地方(Log是debug用的)



[Android] java.net.BindException(address already in use) 錯誤訊息 解決方法 / UDP

在寫UDP的時候遇到了一個問題:

java.net.BindException(address already in use)

這個意思是說你在短時間內訪問過多次這個port

解決方法有2種

1) 修改Port,理由是:有可能你的電腦其他程式也在使用此port,因此造成Error
     (第一次修改後有成功,後來不成功所以又找到第二種方法)

2) 減緩你訪問Port的次數,比方說Thread.Sleep(1000)就改成2000,3000,4000,....等,請自行測試
     (修改成10000時,就沒有出現此問題了)

Android UDP的傳送端較容易產生此問題,End.

2014年8月11日 星期一

[Android/Java] Thread(執行緒)的使用+UDP Send / Receive+Socket

在使用Thread的時候,必須要先知道執行緒(Thread)是甚麼?

否則只是看看範例,卻只得其一不得其二。

執行緒是一種可以在程式背景執行的一個Process(程序),同時可以有多個執行緒一起執行。

由於可以多線程,因此大大增加可用性。

Thread的結構大概就是

public class ChatServer extends Thread{

private DatagramSocket server = null;
private static final int PORT = 4000;
        //宣告變數

public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
        //建構子

public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}
        //主要在跑的地方(主程式)

在呼叫Thread的時候,以上面範例為例,我們呼叫時使用:  

       chatserver = new ChatServer();
       new這個class,他會跑進建構子裡面,但還不會進去run()函式
       chatserver.start();
       執行run()這個函式,由於run裡面有while()迴圈,所以會一直跑不停

       (在這兩行外面要夾try catch否則會有error)

-----------------------------------------------------------------------------------------------------------
上面解釋完Thread了,下面要講的是如何在Android上面使用執行緒的概念做UDP的發送與接收,

但這目前有個問題就是模擬器(emulator)與電腦的連線還沒有試做成功,在Emulator-Emulator是可

以成功傳送-接收的。

傳送部分:

目標:寫一個Thread,讓他不停傳送給指定IP+指定Port

內容:

public class ChatSender extends Thread{

public void run(){
DatagramSocket socket = null;
try
{
socket = new DatagramSocket();
InetAddress serverAddress = InetAddress.getByName("127.0.0.1");
Log.d("IP Address", serverAddress.toString());
String str = "Test Thread sender";
               //創建一個用於發送的DatagramPacket對象
               DatagramPacket packet=new DatagramPacket(str.getBytes(),str.length(),serverAddress,4000);
            //發送數據
            while(true)
            {
            socket.send(packet);
            Thread.sleep(1000);
            }
}
catch(SocketException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(UnknownHostException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(IOException e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
catch(Exception e)
{
e.printStackTrace();
String error = e.toString();
Log.e("Error by Sender", error);
}
finally{
if(socket != null){
socket.close();
}

}
}
}

大概可以看到DatagramSocket+DatagramPacket這兩個API,

DatagramSocket我的理解是用於Socket連線,而DatagramPacket則是負責傳送的封包內容。

*DatagramPacket(封包的byte[]陣列,封包的長度,IP位址,Port); 

至於InetAddress的部分是為了要確定本機IP是多少。


接收部分:

目標:寫一個Thread,讓他不停到指定的Port接收封包,直到有接收到才印出來,之後繼續hold住等待封包傳送過來。

內容:

public class ChatServer extends Thread{

private DatagramSocket server = null;
private static final int PORT = 4000;

public ChatServer() throws IOException {
server = new DatagramSocket(PORT);
Log.d("User","new server socket");
}
public void run(){
byte[] byte100 = new byte[100];
DatagramPacket dPacket = new DatagramPacket(byte100, 100);
String txt;
try{
Log.d("User","runing run()");
while(true){
server.receive(dPacket);
Log.d("User","While 1");
while(true)
{
//印出來到螢幕上
Log.d("User","While 2");
if(true) break;
}
//CloseSocket(client);//關閉
}
}
catch(IOException e)
{}
}

private void CloseSocket(DatagramSocket socket) throws IOException{
socket.close();
}
}

UDP接收的部分同樣也需要DatagramSocket/DatagramPacket,不過剛剛是Send 現在則是receive

為了存放接收的資料,前面會先new一個byte[]陣列用以存放資料。

在server.receive(dPacket);這邊如果沒有資料進來的話,他不會往下跑,會一直等待在這邊,直到接

收到資料才會執行下一行。這是必須特別注意的!


MainActivity的部分:

public class MainActivity extends ActionBarActivity {

private Handler exHandler;
private TextView txv;
private ChatServer chatserver;
private ChatSender chatsender;
public static InetAddress IP;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txv = (TextView) findViewById(R.id.textView);
try{
//IP = InetAddress.getLocalHost();
chatserver = new ChatServer();
chatserver.start();
chatsender = new ChatSender();
chatsender.start();
Log.d("User","Thread start...");
}catch(Exception e)
{
String str = e.toString();
Log.e("Error by User", str);
}
}
protected void onPause(){
super.onPause();
if(chatserver != null)
{
if(!chatserver.isInterrupted())
{
chatserver.interrupt();
}
}
}
} 

然後要記得AndroidManifest.xml這邊要增加INTERNET的Uses-Permission

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.thread_example"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.thread_example.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


結論: UDP 傳送及接收其實不容易,看似簡單但很多細節如果沒有注意到就會失敗!