Cơ bản về J2ME Bluetooth: Bài 2: Mô hình ứng dụng


Bài thứ 2 này sẽ nói đến các bước mà các ứng dụng J2ME trao đổi với nhau qua Bluetooth.

Trước khi xem bài này, bạn nên xem qua bài 1
Giờ thì ta cùng bắt đầu vào nội dung mới.

Client-Server. Đó là mô hình mà các ứng dụng J2ME trao đổi với nhau qua Bluetooth. Điều này có nghĩa là để 2 ứng dụng J2ME trao đổi được với nhau thì một anh phải đóng vai trò Server (cung cấp dịch vụ), một anh phải đóng vai trò Client (sử dụng dịch vụ do anh kia cung cấp). Kết nối giữa Client và Server qua Bluetooth có thể là một trong 3 loại sau đây:
  1. OBEX : Giao thức Object Exchange dùng để trao đổi những dữ liệu như File, Hình ảnh và các dữ liệu dạng nhị phân khác
  2. L2CAP - Logical Link Control and Adaptation Protocol dùng để gửi những gói tin giữa Server và Client
  3. RFCOMM - Radio Frequency Communication là giao thức dễ sử dụng, không phức tạp để trao đổi những dữ liệu đơn giản

Mô hình hoạt động của ứng dụng Client và Server trong J2ME Bluetooth


Bước Server Application Client Application
1 Quản lý thiết bị, thiết lập chế độ nhận biết Quản lý thiết bị, thiết lập chế độ nhận biết
2 Mở kết nối Bluetooth, đăng ký dịch vụ Nhận biết các thiết bị Bluetooth xung quanh
3 Chờ client kết nối Nhận biết dịch vụ trên thiết bị Bluetooth đã nhận ở bước trên
4   Nếu tìm thấy dịch vụ cần thiết, tiến hành kết nối tới dịch vụ đó
5 Mở các dòng nhập xuất dữ liệu để trao đổi thông tin Mở các dòng nhập xuất dữ liệu để trao đổi thông tin
  1. Quản lý thiết bị và thiết lập chế độ nhận biết:

    Trước khi mở kết nối, ta cần làm cho thiết bị Bluetooth ở trạng thái có thể nhận biết bằng phương thức setDiscoverable(….) của đối tượng LocalDevice

    LocalDevice lDevice=LocalDevice.getLocalDevice();
    lDevice.setDiscoverable(DiscoveryAgent.GIAC);

    Trong đó,
    • Phương thức LocalDevice.getLocalDevice() trả về đối tượng cung cấp các chức năng tương tác với thiết bị Bluetooth hiện tại mà ứng dụng đang chạy trên đó. 
    • Hằng số GIAC (General/Unlimited Inquiry Access Code): thiết lập thiết bị Bluetooth hiện tại ở chế độ nhận biết thông thường, không giới hạn.
  2. Mở kết nối Bluetooth:

    Sử dụng Connector.open(url[, mode][, timeout])
    Thông thường url ở dạng scheme://host:port;parameters
    Trong đó:
    -         scheme:      chỉ định loại kết nối
    -         host:           dùng cho kết nối phía client để chỉ định địa chỉ mà nó kết nối tới hoặc dùng localhost cho kết nối phía server.
    -         port:           Với kết nối phía client, nó chỉ định kênh dịch vụ. Với kết nối phía server, nó chỉ định định danh (UUID) của dịch vụ.
    -         parameters:Tùy chọn, có thể chỉ định tên hoặc kích thước MTU (Maximum Transition Unit)
    • RFCOMM
      • URL Scheme: btspp
      • Client Connection: StreamConnection
      • ServerConnection: StreamConnectionNotifier, StreamConnection
    • L2CAP
      • URL Scheme: btl2cap
      • Client Connection: L2CAPConnection
      • ServerConnection: L2CAPConnectionNotifier, L2CAPConnection
    ví dụ:

    final String MY_SERVICE_NUMBER= "0987654321234567890ABCDEFABCDEF";
    UUID myUUID=new UUID(MY_SERVICE_NUMBER, false);
    String url="btspp://localhost:" + myUUID.toString() + ";name=testSRV";
    notifier =(StreamConnectionNotifier) Connector.open(url);

     

  3. Đăng ký dịch vụ cho Server

    ServiceRecord sr=ld.getRecord(notifier);
  4. Chờ client kết nối

    StreamConnection sc=notifier.acceptAndOpen();
  5. Nhận biết các thiết bị Bluetooth xung quanh

    Để bắt đầu nhận biết các thiết bị Bluetooth xung quanh, ta gọi đến phương thức LocalDevice.startInquiry(...) và truyền vào đó cách thức nhận biết là DiscoveryAgent.GIAC hoặc DiscoveryAgent.LIAC.
    Lớp xử lý cho Client lúc này cần thi hành giao diện DiscoveryListener, trong đó có 2 phương thức sẽ được dùng cho nhận biết thiết bị:
    • void deviceDiscovered(RemoteDevice btDevice, DeviceClass cod)
      Được thực thi khi nhận biết được 1 thiết bị, thông tin về thiết bị đó nằm trong đối tượng RemoteDevice. Client có thể nhận biết được nhiều thiết bị khác và thông thường, khi nhận biết được một thiết bị, ta lưu lại thông tin về thiết bị đó để phục vụ việc kết nối sau này.
    • void inquiryCompleted(int discType)
  6. Nhận biết các dịch vụ trên các thiết bị đã biết

    Khi DiscoveryAgent tiến hành searchServices(....) trên 1 RemoteDevice, quá trình tìm kiếm dịch vụ trên thiết bị đó sẽ bắt đầu, 2 phương thức sau của giao diện DiscoveryListener sẽ được dùng đến trong quá trình này:
    • void servicesDiscovered(int transID, ServiceRecord[] records)
      Được thực thi khi nhận được các dịch vụ trên thiết bị đã chỉ định. Ta có thể lưu lại thông tin về tất cả các dịch vụ đã tìm được hoặc chỉ quan tâm tới 1 dịch vụ đã biết trước nào đó thôi.

    public void servicesDiscovered(int transID, ServiceRecord[] records){       
            for(int i=0; i<records.length; i++){
                url=records[i].getConnectionURL( ServiceRecord.AUTHENTICATE_ENCRYPT, false);
                isServiceFound= (url.indexOf("name=testSRV")>=0);           
                if (isServiceFound){           
                    this.si.setText("Service is found");
                    break;
                }
            }       
        }

    • void serviceSearchCompleted(int transID, int respCode)
      Được thực thi khi quá trình tìm kiếm dịch vụ hoàn tất. Ta sẽ xét trong những dịch vụ đã tìm được để lấy thông tin kết nối tới dịch vụ mong muốn rồi tiến hành mở kết nối tới dịch vụ đó

    public void serviceSearchCompleted(int transID, int respCode){
            if (isServiceFound){   
                try{
                    //cho client, dung StreamConnection thay vi StreamConnectionNotifier
                    sc=(StreamConnection) Connector.open(url);
                    ........
                }catch(Exception ex){
                    ex.printStackTrace();
                }
            }
        }
  7. Trao đổi thông tin:

    Sau khi Client kết nối tới 1 dịch vụ của Server thì quá trình chờ ở server gây ra bởi acceptAndOpen() sẽ kết thúc và các dòng lệnh tiếp sau nó sẽ được thực hiện. Lúc này, ta mở ra các dòng nhập xuất dữ liệu cho Server và cả Client
    DataInputStream dis=sc.openDataInputStream();
    DataOutputStream dos=sc.openDataOutputStream();

    Việc nhận thông tin ở Server và ở Client cần được lặp đi lặp lại và liên tục bởi ta không biết lúc nào thì phía kia sẽ gửi. Công việc này nên được thực hiện trong một luồng độc lập.
    Việc gửi thông tin có thể để người dùng chủ động quyết định lúc nào thì gửi, ta chỉ cần "write" dữ liệu đó vào DataOutputStream mà thôi.

Bài 3: Viết ứng dụng Server & Client


( đã được xem 7355 lần từ 30/03/2009 )

Phản hồi bài viết

   
Họ tên  
Email*
Mã xác thực email
Tiêu đề*
Nội dung*
Đính kèm 
 
 
Hữu Dũng huudung@...
re Cuong
Em có thể tìm thấy câu trả lời đó ở đây
http://en.wikipedia.org/wiki/Universally_Unique_Identifier#Java

Trong ví dụ trên, tôi tạo 1 xâu ngẫu nhiên gồm các chữ cái, chữ số rồi truyền vào cho lớp UUID để tạo ra giá trị UUID dạng đầy đủ.
 anh_cuong1432@...
UUID?
Thầy cho em hỏi là cái UUID có thể đặt tự do không, hay có quy tắc nào để đặt?
Trang 1
Tôi là Lê Hữu Dũng
Giảng viên CNTT
Khoa Công nghệ Tin học
Viện Đại học Mở Hà Nội