元派遣プログラマの自称技術系ブログです。雑記とか自作のオープンソースプロジェクトの話とか。
Javaとか組込とかできます。お仕事ください。

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(;;){}
}

追記

アプリケーションを実装しようとすると使い物にならないので、再設計中です。ごめんなさい。