昨日、ファイルを送信するときに、モバイルクライアント(Symbian 9.1、Series 60のMobile Python)と通信するサーバープログラム(Fedora 10、C)が失敗し始めたという事実に直面しました。
_____________________________________________________
PS:誰もアドバイスをくれなかったのは残念です...しかし、彼女自身はそれを理解しました。 write()関数によって返される値を制御する必要があることがわかりました。実際、プログラムが送信しようとしたバイト数よりも少ないバイト数を送信できます。 バイトの配列を送信しようとすると、実際に送信されたバイト数を確認する価値があります。_____________________________________________________
昨日まで失敗はありませんでした。 同時に、サーバープログラムのデバッグプリントは、ファイルが完全に送信されたことを示します。 クライアントアプリケーションのデバッグ印刷は、ファイルが完全に読み取られていないことを示しています。 クライアントとサーバーのコードは変更されず、コンピューターと電話のソフトウェアを更新しませんでした。新しいものをインストールしませんでした。
他のファイルは、同じプログラムによってサーバーから電話に完全に送信され、その逆も同様です。 問題は、送信されたjarファイルの新しいバージョンにのみあります。20Kから38Kに増加しました。 送信されたファイルのコードを見て、FFのようなバイトの転送が中断されたかどうかを確認しました-いいえ、この時点でバイトのシーケンスは非常に普通でした:... 00 60
39 00 00 ...(39-最後に送信されたバイト)。
問題はソケットへの出力のバッファリングにあると思われます。サーバーはすべての情報を送信しなかったため、クライアントは情報の全量が送信されるのを待ちます。 サーバーとクライアントを毎日継続的に使用していることは奇妙ですが、このエラーは初めて現れました。 しかし、私はまだフラッシュソケットを作成する方法を見つけていません(fflush(bt-> socketClient)はセグメンテーションエラーを与えます-そして、私が理解するように、以下に説明する方法で作成されたソケットには適用できません)。
ソケットを作成し、それを介してファイルを送信しようとするコードは次のとおりです。
struct BT_SDESC {
符号なし文字チャネル。
unsigned int uuid;
char * serviceName;
char * serviceDescription;
char * serviceProvider;
void *セッション;
int hciID;
};
// Bluetoothサーバー
BT_SRV構造体{
struct BT_SDESC * sd;
int socketClient;
int socketServer;
};
...
struct BT_SDESC * btBuildSDesc(intチャネル){
struct BT_SDESC * sd;
sd =(struct BT_SDESC *)malloc(sizeof(struct BT_SDESC));
if(!sd){
NULLを返します。
}
memset(sd、0、sizeof(struct BT_SDESC));
sd-> channel = channel;
sd-> uuid = 0xAFFF; / * TODO:この値を確認してください* /
if(!(sd-> serviceName = strdup( "TeleComp:W-Shell"))
|| !(sd-> serviceDescription = strdup(「ウェアラブルコンピューターのユーザーシェル」))
|| !(sd-> serviceProvider = strdup( "kiborgov.net"))
){
btDestroySDesc(sd);
NULLを返します。
}
sdを返します。
}
int btSDescribe(struct BT_SDESC * sd){
uint32_t serviceUuidInt [] = {0,0,0、sd-> uuid};
uuid_t serviceUuid、rootUuid、l2capUuid、rfcommUuid;
sdp_record_t * record = sdp_record_alloc();
sdp_session_t * session = NULL;
sdp_list_t * rootList = NULL、* svClassID = NULL、* profilesList = NULL、* l2capList = NULL、* protocolList = NULL、* rfcommList = NULL、* accessProtocolList = NULL;
sdp_profile_desc_tプロファイル;
sdp_data_t * channel = NULL;
int ret = -2;
/ *一般サービスIDを設定* /
sdp_uuid128_create(&serviceUuid、&serviceUuidInt);
sdp_set_service_id(レコード、serviceUuid);
/ *公共サービスの記録* /
sdp_uuid16_create(&rootUuid、PUBLIC_BROWSE_GROUP);
rootList = sdp_list_append(0、&rootUuid);
sdp_set_browse_groups(レコード、rootList);
/ *ポート属性を設定* /
sdp_uuid16_create(&rootUuid、SERIAL_PORT_SVCLASS_ID);
svClassID = sdp_list_append(0、&rootUuid);
sdp_set_service_classes(レコード、svClassID);
sdp_uuid16_create(&profile.uuid、SERIAL_PORT_PROFILE_ID);
profile.version = 0x100;
profilesList = sdp_list_append(0、&profile);
sdp_set_profile_descs(レコード、profilesList);
/ * l2cap情報を設定* /
sdp_uuid16_create(&l2capUuid、L2CAP_UUID);
l2capList = sdp_list_append(0、&l2capUuid);
protocolList = sdp_list_append(0、l2capList);
/ * rfcomm情報を設定* /
sdp_uuid16_create(&rfcommUuid、RFCOMM_UUID);
channel = sdp_data_alloc(SDP_UINT8、&(sd-> channel));
rfcommList = sdp_list_append(0、&rfcommUuid);
sdp_list_append(rfcommList、チャンネル);
sdp_list_append(protocolList、rfcommList);
/ *サービスレコードにプロトコル情報を添付* /
accessProtocolList = sdp_list_append(0、protocolList);
sdp_set_access_protos(レコード、accessProtocolList);
/ *名前、プロバイダー、説明を設定* /
sdp_set_info_attr(レコード、sd-> serviceName、sd-> serviceProvider、sd-> serviceDescription);
/ *ローカルSDPサーバーを接続し、サービスレコードを登録してから切断します* /
if((session = sdp_connect(BDADDR_ANY、BDADDR_LOCAL、SDP_RETRY_IF_BUSY))){
ret = sdp_record_register(セッション、レコード、0);
}
/ *割り当てられたリソースを解放* /
sdp_data_free(チャネル);
sdp_list_free(l2capList、0);
sdp_list_free(rfcommList、0);
sdp_list_free(rootList、0);
sdp_list_free(accessProtocolList、0);
sdp_list_free(svClassID、0);
sdp_list_free(profilesList、0);
sd-> session =(void *)session;
return ret;
}
int btBuildSocket(unsigned intチャネル、struct BT_SDESC * sd){
struct sockaddr_rc localAddr;
int s = -1、res = -1;
if((sd-> hciID = btCheckDevice())==-1){
return -1;
}
if(hci_open_dev(sd-> hciID)<0){
return -1;
}
hci_close_dev(sd-> hciID);
memset(&localAddr、0、sizeof(struct sockaddr_rc));
if((s = socket(AF_BLUETOOTH、SOCK_STREAM、BTPROTO_RFCOMM))==-1){
return -1;
}
/ * TODO:以下のコードをSDPを使用するコードに置き換えてください* /
localAddr.rc_family = AF_BLUETOOTH;
localAddr.rc_bdaddr = * BDADDR_ANY;
localAddr.rc_channel =(uint8_t)チャネル;
if((res = bind(s、(struct sockaddr *)&localAddr、sizeof(localAddr)))==-1){
閉じる(s);
return -1;
}
return s;
}
struct BT_SRV * btStartServer(intチャネル){
struct BT_SRV * bt = malloc(sizeof(struct BT_SRV));
if(!bt){
btErr = BT_ERR_START_SERVER;
btKillServer(bt);
NULLを返します。
}
memset(bt、0、sizeof(struct BT_SRV));
bt-> socketServer = bt-> socketClient = -1;
btErr = BT_OK;
if(btCheckDevice()<0){
btErr = BT_ERR_NO_DEVICE;
btKillServer(bt);
NULLを返します。
}
if(!(bt-> sd = btBuildSDesc(channel))){
btErr = BT_ERR_SDESC_CREATION;
btKillServer(bt);
NULLを返します。
}
if(btSDescribe(bt-> sd)==-1){
btErr = BT_ERR_SDESC_REGISTRATION;
btKillServer(bt);
NULLを返します。
}
if((bt-> socketServer = btBuildSocket(channel、bt-> sd))==-1){
btErr = BT_ERR_BUILD_SOCKET;
btKillServer(bt);
NULLを返します。
}
if(listen(bt-> socketServer、10)){
btErr = BT_ERR_SOCKET_LISTENING;
btKillServer(bt);
NULLを返します。
}
return bt;
}
...
struct BT_SRV * bt = NULL;
int sendFileToClient(char * fname){
static char buf [1024];
int h;
long int bufsize = 1024;
long int sent = 0;
long intがロードされました。
struct stat stbuf;
logPrint( "ファイルの送信\"%s \ "クライアントへ。"、fname);
if(stat(fname、&stbuf)==-1){
logPrint( "エラー:ファイル情報を取得できません。");
return -1;
}
if((h = open(fname、O_RDWR))<1){
logPrint( "エラー:ファイルを開けません。");
return -2;
}
sprintf(buf、「%010ld」、stbuf.st_size);
logPrint( "Sending%ld bytes of data ..."、stbuf.st_size);
書き込み(bt-> socketClient、buf、10);
while(送信済み<stbuf.st_size){
loaded =(stbuf.st_size> bufsize)?bufsize:stbuf.st_size;
loaded = read(h、&buf、loaded);
if(loaded <1){
休憩;
}
送信済み= =ロード済み。
書き込み(bt-> socketClient、buf、loaded);
logPrint( "送信済み:%ld"、送信済み);
}
閉じる(h);
logPrint(「ファイルが送信されました。%ldバイトが送信されました。」、送信);
返送済み;
}
...
bt = btStartServer(cfgBtChannel);
...
bt-> socketClient = accept(bt-> socketServer、NULL、NULL);
fcntl(bt-> socketClient、F_SETFL、O_NONBLOCK);
sendFileToClient( "./ projects / cloud / bin / Cloud.jar");
クラッシュが発生するファイル転送は、1つの(場合の80%で)ファイルの場所で中断し、2番目(残りの20%で)で中断します。