/** * FTPM(FTPもどき) * Server側プログラム * * 常時ファイル受信待ち * 受信ファイルサイズはserver.confで変更可能 * 受信ファイルはdownloadフォルダに保存 * * **/ #include <stdio.h> #include <string.h> #include <stdbool.h> #include <nstdc_socket.h> #define READ_SIZE 256 #define FILE_NAME_MAX 100 void printSockInf( struct sockaddr_in* inf ); int getByteData( int data, int dataPos ); bool recvCommand( int sock ); void recvData( int sock ); void getFileName( int sock ); void getData( int sock ); FILE *fp; int main( void ) { int socket0; /* bindするsocketの識別子 */ struct sockaddr_in addr; /* サーバー自身の情報 */ struct sockaddr_in client; /* クライアントの情報 */ socklen_t len; /* クライアント情報のサイズ */ int sock; /* 接続するsocketの識別子 */ int ret; /* 戻り値 */ int yes = 1; char inbuf[READ_SIZE]; /* 受信データ領域 */ /* 領域初期化 */ memset( inbuf, 0, sizeof( inbuf )); /* ソケットの生成 */ socket0 = socket( AF_INET, SOCK_STREAM, 0 ); if( socket0 < 0 ){ perror("socket"); return 1; } /* ソケットの設定 */ addr.sin_family = AF_INET; /* IPv4 */ addr.sin_port = htons( 21080 ); addr.sin_addr.s_addr = INADDR_ANY; setsockopt( socket0, SOL_SOCKET, SO_REUSEADDR, (const char*)&yes, sizeof(yes)); ret = bind( socket0, ( struct sockaddr * )&addr, sizeof( addr ) ); if( ret != 0 ){ perror("bind"); return 1; } /* TCPクライアントからの接続要求を待てる状態にする */ ret = listen( socket0, 5 ); if( ret != 0 ){ perror("listen"); return 1; } /* 繰り返し接続可能にする */ while(1) { /* TCPクライアントからの接続要求を受け付ける */ len = sizeof( client ); sock = accept( socket0, ( struct sockaddr *)&client, &len ); if( sock < 0 ){ perror( "accept" ); return 1; } /* 接続情報の表示 */ printf("accepted connection from IP:"); printSockInf(&client); /* データを受信する */ recvData( sock ); /* TCPセッションの終了 */ while( recv( sock, inbuf, sizeof( inbuf ) - 1, 0 ) > 0 ) { } close( sock ); } /* listenするsocketの終了 */ close( socket0 ); return 0; } /* データを受信する */ void recvData( const int sock ){ bool isEnd = false; /* データ受信が完了するまでコマンド別の処理を実行する */ while( !isEnd ){ isEnd = recvCommand( sock ); } } /* コマンドを受信・実行する */ bool recvCommand( const int sock ){ char command; char commandEnd; bool isLastCommand = false; /* コマンドを受信する */ recv( sock, &command, 1, 0 ); recv( sock, &commandEnd, 1, 0 ); printf(" RECV = %s\n", &command ); if( commandEnd != ':' ){ printf("ERROR NO COMMAND.\n"); return true; } /* コマンドを解析し、コマンド別の処理を実行する */ switch( command ){ case 'n': /* ファイル名指定コマンド */ printf("command FileName\n"); /* ファイル名を読み取って書き込みファイルを作成する. */ getFileName( sock ); break; case 't': /* ファイル送信コマンド */ printf("command File\n"); /* readが空になるまで読み取りファイルに書き込む。 */ getData( sock ); isLastCommand = true; break; default : break; } return isLastCommand; } /* ファイル名を読み取り、同名のファイルを生成・オープンする */ void getFileName( int sock ){ char read; char fname[FILE_NAME_MAX]; int i = 0; printf("getFileName\n"); /* 一文字ずつ改行コードまで読み取る */ recv( sock, &read, 1, 0); while( read != '\n' ){ // printf("%c\n",read); fname[i] = read; recv( sock, &read, 1, 0 ); i++; } fname[i] = '\0'; printf("fileName = %s \n", &fname ); /* 読み取ったファイル名でファイルをオープンする */ fp = fopen( fname, "w"); if( fp == NULL ){ printf("ERROR File not open.\n"); return; } } /* データをすべて受信しオープン済みのファイルに書き込む */ void getData( int sock ){ char buf[READ_SIZE]; /* データをすべて読み取りファイルに書き込む */ size_t size = recv(sock, buf, READ_SIZE, 0); while( size > 0 ){ printf("size = %d\n%s\n", size, buf); fwrite( buf, sizeof( char ), size, fp ); size = recv(sock, buf, READ_SIZE, 0); } /* ファイルをクローズする */ fclose( fp ); return; } /* socket情報からアドレス情報を表示する */ void printSockInf( struct sockaddr_in* inf ){ in_addr_t addr; /* IPアドレス */ addr = ntohl( inf->sin_addr.s_addr ); printf( "%d.%d.%d.%d(%d)\n", getByteData( addr, 3 ), getByteData( addr, 2 ), getByteData( addr, 1 ), getByteData( addr, 0 ), inf->sin_port); return; } /* 指定のデータ(int32)から指定位置の1Byteを返す * dataPos : data内の位置指定(右端から0オリジン) [3][2][1][0] */ int getByteData( int data, int dataPos ){ return (( data >> ( dataPos * 8 )) & 0xFF ); } /* ----- EOF ----- */