LPC1769用TCPサーバ、一応完成
過負荷時の安定性には難有ですが、とりあえず動きはしました。
1セッションなら大体2〜3Mbps。200kbpsくらいの転送制限をかければ、5〜6本程度まで同時に捌けます。転送レートが低ければ、20本くらいまで接続を維持するはずです。たぶん。
現状の問題
現段階で判っている問題は結構あります。
- TCP ZerowindowProbeを処理しない。
- UIPとの二重管理のため、メモリ効率が悪い。(1ソケット辺り300バイトくらい使う。)
- コネクトから通信の開始までに、最小で0.5秒のラグがある。
- 複数セッションで連続送信をマトモに扱えるのは3接続くらいまで。
- 接続に失敗すると容赦なく切断する。
でもまあ、UIPをそのまま使うよりも簡単にサーバを実装できるとは思います。
ソースはもうちょっといじったら公開します。
検証用スケッチ
23番ポートで受け付けて、受信したパケットをオウム返しします。
/** * Nyarudinoのスケッチシステムを使う場合の実装 */ #include "boot/sketch.h" #include "NyLPC_uipService.h" #include "NyLPC_stdlib.h" #define NUM_OF_TH 20 NyLPC_cThread_t thread[NUM_OF_TH]; NyLPC_TcTcpSocket_t sock[NUM_OF_TH]; /** * セットアップ(NUM_OF_TH個のスレッドを準備) */ void setup(void) { int i; //EthernetAddressのセット NyLPC_TEtherMacAddr_t mac=NyLPC_TEtherMacAddr_pack(0x00,0x12,0x13,0x10,0x15,0x11); //uipサービスの初期化 NyLPC_cUipService_initialize(&mac); for(i=0;i<NUM_OF_TH;i++){ NyLPC_cThread_initialize(&thread[i],128); NyLPC_cTcpSocket_initialize(&sock[i]); } } /** * 送受信スレッド */ void mtproc(NyLPC_TcTcpSocket_t* i_s) { NyLPC_TUInt32 sl; int i,i2; char* d; i2=0; //とりあえずデータ受信して閉じる。 while(1){ if(NyLPC_cTcpSocket_recv(i_s,&d,&sl,portMAX_DELAY)){ i2+=sl; i=0; if(sl>0){ do{ if(!NyLPC_cTcpSocket_send(i_s,d,sl,&i,portMAX_DELAY)){ NyAR_DebugHook(); NyLPC_cTcpSocket_send_close(i_s); NyLPC_cTcpSocket_recv_close(i_s); return; } sl-=i; d+=i; }while(sl>0); }else{ NyAR_DebugHook(); NyLPC_cTcpSocket_send_close(i_s); NyLPC_cTcpSocket_recv_close(i_s); return; } }else{ NyLPC_cTcpSocket_send_close(i_s); NyLPC_cTcpSocket_recv_close(i_s); return; } } } /** * メイン関数。listen待機して、必要に応じてスレッドを起動。 */ void loopback(void) { int i; //IPアドレスの設定 NyLPC_TIpv4Addr_t ipaddr=NyLPC_TIpv4Addr_pack(192,168,128,201); NyLPC_TIpv4Addr_t netmask=NyLPC_TIpv4Addr_pack(255,255,255,0); NyLPC_TIpv4Addr_t gateway=NyLPC_TIpv4Addr_pack(192,168,128,254); NyLPC_TcTcpListener_t li; NyLPC_cUipService_start(&ipaddr,&netmask,&gateway); //Uipの開始 NyLPC_cTcpListener_initialize(23,3,&li); //リスナ生成(23番、キュー数3) NyLPC_cUipService_addListener(&li); //リスナadd for(;;){ for(i=0;i<NUM_OF_TH;i++){ //フリーなスレッドを探す。 if(NyLPC_cThread_isTerminated(&thread[i])){ //listen処理 if(NyLPC_cTcpListener_listen(&li,&sock[i],10000/portTICK_RATE_MS)){ //listen通ったらThread起動 NyLPC_cThread_start(&thread[i],(NyLPC_cThread_ThreadFunc)mtproc,&sock[i]); } break; } } vTaskDelay(10/portTICK_RATE_MS); } } void loop(void) { loopback(); for(;;){} }
追記
アプリケーションを実装しようとすると使い物にならないので、再設計中です。ごめんなさい。