ネットワークプログラミング——TCPファイル転送
29267 ワード
ネットワークプログラミング——TCPファイル転送ネットワークプログラミングTCPファイル転送 要求 構想 結果 コード クライアント サービス
要求
-クライアントはサービス側にsocket接続を開始し、データ伝送チャネルを確立する
-クライアントは、送信するファイル名をサービス側に送信し、'#'文字で終わり、サービス側は文字ごとに受け入れ、'#'を受信したことを知っています.
-クライアントがサービス側にファイル長、4バイトを送信
-クライアントがサービス側にファイル内容を送信する-サービス側がファイルを受信した後、「OK」を送信する
-クライアントは「OK」を受信し、ソケットを閉じる
構想
-socket接続は、以前のクライアントおよびサービス側とほぼ同じであり、主にデータ受信伝送のプロセスが処理する必要がある.
-クライアントはファイル名を転送し、ファイル名の後ろに「#」を付けるには、出入りパラメータを処理し、コマンドラインパラメータを配列に読み込み、配列の最後に「#」を付け、転送は配列の形式で行われる必要があります.
-ファイルの種類はテキストファイルに限らないので、処理時にC++をバイナリファイルとして扱うべきファイルストリームにはread()とwrite()関数が用意されており、バイナリデータを一度に一定の大きさで読み取り、書き込むのが便利です.
-転送ファイルの内容の長さが4バイトで、4バイトでほとんどのファイル転送要件を満たす
-ファイル
-バッファサイズが限られています.また、大きなファイルを転送する場合、バッファサイズがファイル長より小さい可能性が高いので、処理するときはループ処理し、送信するにはループ送信し、受信するにはループ受信、書き込みする必要があります.C++のファイルストリームにはread()とwrite()関数が用意されており、バッファサイズを超える転送データのためにこの2つの関数を呼び出し続けています.
-ファイル長を複数回転送する必要がある場合は、受信するたびに情報が印刷されます.
-ファイルコンテンツを転送する際には、主に前に受信したファイル長に基づいて、一定長データ受信関数を呼び出してデータ受信を行う.
-転送ファイルの長さについては、配列による参照ができない4バイトの配列で表される長さと、4バイトの整数で表される長さの範囲が異なり、整数で表される範囲が配列よりはるかに大きいことに注意してください.
-ファイルの長さを転送するときはパラメータの設定に注意
-転送が終了した後、サービス側はファイル転送が終了した旨のメッセージを印刷し、クライアントに情報を返す.
-クライアントはOKメッセージを受け取った後、終了する.
-サービス側は、問題が発生した場合、closesocketを返し、受信ファイル全体がwhileループであるため、受信に失敗した場合など、他の問題が発生した場合、continueは最初のエラー処理(クライアントが操作に失敗して接続を閉じた場合)に、closesocketとreturnを統一的に行うことに注意を返します.
結果
-クライアント・パラメータは、転送先IPアドレス、ポート番号、および転送するファイル名を設定します.
-ファイル情報はPDFファイルで、サイズは
-クライアントがサービス側と対話して実行した結果:クライアントは、上記の図から、クライアントがファイル名の転送、ファイル長の転送、ファイルの送信に成功した後に、サービス側が返した確認情報の印刷を行うことができることを示しています.確認を得て終了します.
サービス側
図から分かるように、サービス側はクライアントのアドレスとポート情報を得ることができ、受信するファイル名、ファイルの長さを印刷することができる.同時に、ファイルの受信が完了したときにヒントを与え、ファイルの内容を印刷します.最後にクライアントに確認情報を送信します.クライアントは確認された後に終了します.
転送ファイルが大きすぎると、サービス側はデータをループして受信し、受信するたびに関連情報を印刷する.
また,クライアントのファイルディレクトリの下には,伝達されたデータが見られ,正常に開くことができ,実験結果は要求に達した.
コード#コード#
クライアント
サービス側
要求
-クライアントはサービス側にsocket接続を開始し、データ伝送チャネルを確立する
-クライアントは、送信するファイル名をサービス側に送信し、'#'文字で終わり、サービス側は文字ごとに受け入れ、'#'を受信したことを知っています.
-クライアントがサービス側にファイル長、4バイトを送信
-クライアントがサービス側にファイル内容を送信する-サービス側がファイルを受信した後、「OK」を送信する
-クライアントは「OK」を受信し、ソケットを閉じる
構想
-socket接続は、以前のクライアントおよびサービス側とほぼ同じであり、主にデータ受信伝送のプロセスが処理する必要がある.
-クライアントはファイル名を転送し、ファイル名の後ろに「#」を付けるには、出入りパラメータを処理し、コマンドラインパラメータを配列に読み込み、配列の最後に「#」を付け、転送は配列の形式で行われる必要があります.
//
char filename[MAX_PATH];
int i = 0;
for (i = 0; i 3][i];
}
filename[i++] = '#';
//
iResult = send(ConnectSocket, filename, strlen(filename), 0);
if (iResult == SOCKET_ERROR)
{
cout <"Send Filename : " <" with error " <"
" <break;
}
-ファイルの種類はテキストファイルに限らないので、処理時にC++をバイナリファイルとして扱うべきファイルストリームにはread()とwrite()関数が用意されており、バイナリデータを一度に一定の大きさで読み取り、書き込むのが便利です.
//
ifstream sourcefile(argv[3], ios::in | ios::binary);
sourcefile.read(filebuf, MAX_LEN);
rec_file.write(Recvb, MAX_LEN);
-転送ファイルの内容の長さが4バイトで、4バイトでほとんどのファイル転送要件を満たす
-ファイル
//
int len;
FILE* fp;
if(fp = fopen(argv[3], "r"))
{
fseek(fp, 0, SEEK_END);
printf("%ld
", ftell(fp));
len = ftell(fp);
fclose(fp);
}
else
{
cout <"Error" <
-バッファサイズが限られています.また、大きなファイルを転送する場合、バッファサイズがファイル長より小さい可能性が高いので、処理するときはループ処理し、送信するにはループ送信し、受信するにはループ受信、書き込みする必要があります.C++のファイルストリームにはread()とwrite()関数が用意されており、バッファサイズを超える転送データのためにこの2つの関数を呼び出し続けています.
sourcefile.read(filebuf, MAX_LEN);
rec_file.write(Recvb, MAX_LEN);
-ファイル長を複数回転送する必要がある場合は、受信するたびに情報が印刷されます.
while (left > 0)
{
if (left > MAX_LEN)
{
iResult = recvn(s, Recvb, MAX_LEN);
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else if (iResult == 0)
{
cout <"Receive data stopped. There "<" bytes unreceived" <break;
}
else
{
cout <"Receive partial data : " <" bytes" <else
{
iResult = recvn(s, Recvb, left);
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else if (iResult ==0 )
{
cout <"Receive data stopped. There " <" bytes unreceived" <break;
}
else
{
cout <"Receive data : " <" bytes" <0;
}
}
}
-ファイルコンテンツを転送する際には、主に前に受信したファイル長に基づいて、一定長データ受信関数を呼び出してデータ受信を行う.
-転送ファイルの長さについては、配列による参照ができない4バイトの配列で表される長さと、4バイトの整数で表される長さの範囲が異なり、整数で表される範囲が配列よりはるかに大きいことに注意してください.
-ファイルの長さを転送するときはパラメータの設定に注意
-転送が終了した後、サービス側はファイル転送が終了した旨のメッセージを印刷し、クライアントに情報を返す.
//
iResult = recv(s, (char*)&len_tran, 4, 0);
if (iResult != 4)
{
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else
{
cout <"Length data is not complete. Connection closed
" <return -1;
}
}
recvlen =ntohl( len_tran);
cout <"The length of file to receive is " <"
" <
-クライアントはOKメッセージを受け取った後、終了する.
-サービス側は、問題が発生した場合、closesocketを返し、受信ファイル全体がwhileループであるため、受信に失敗した場合など、他の問題が発生した場合、continueは最初のエラー処理(クライアントが操作に失敗して接続を閉じた場合)に、closesocketとreturnを統一的に行うことに注意を返します.
iResult = recv(ConnectSocket, RecvBuffer, sizeof(RecvBuffer), 0);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout <"Client(" <" : " <") Exited" <// ,continue , , closesocket
closesocket(ConnectSocket);
return -1;
}
結果
-クライアント・パラメータは、転送先IPアドレス、ポート番号、および転送するファイル名を設定します.
-ファイル情報はPDFファイルで、サイズは
-クライアントがサービス側と対話して実行した結果:クライアントは、上記の図から、クライアントがファイル名の転送、ファイル長の転送、ファイルの送信に成功した後に、サービス側が返した確認情報の印刷を行うことができることを示しています.確認を得て終了します.
サービス側
図から分かるように、サービス側はクライアントのアドレスとポート情報を得ることができ、受信するファイル名、ファイルの長さを印刷することができる.同時に、ファイルの受信が完了したときにヒントを与え、ファイルの内容を印刷します.最後にクライアントに確認情報を送信します.クライアントは確認された後に終了します.
転送ファイルが大きすぎると、サービス側はデータをループして受信し、受信するたびに関連情報を印刷する.
また,クライアントのファイルディレクトリの下には,伝達されたデータが見られ,正常に開くことができ,実験結果は要求に達した.
コード#コード#
クライアント
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#pragma comment (lib,"ws2_32.lib")
using namespace std;
//
#define MAX_LEN 100000
int __cdecl main(int argc, char* argv[])
{
WSADATA ws;
SOCKET ConnectSocket = INVALID_SOCKET;
struct sockaddr_in Server_addr;
int iResult = 0;
int Addrlen = 0;
HANDLE hThread = NULL;
char Sendbuffer[MAX_LEN];
char Recvbuffer[MAX_LEN];
//
if (argc != 4)
{
cout <"Need enter target IP, port and the file name to transmit !" <return -1;
}
int PORT = atoi(argv[2]);
// socket
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout <"Initiate failed with error: " <return -1;
}
// socket
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
cout <"Create Client socket failed with error: " <return -1;
}
Server_addr.sin_family = AF_INET;
Server_addr.sin_addr.s_addr = inet_addr(argv[1]);
Server_addr.sin_port = htons(PORT);
memset(Server_addr.sin_zero, 0x00, 8);
// socket
iResult = connect(ConnectSocket, (struct sockaddr*)&Server_addr, sizeof(Server_addr));
if (iResult != 0)
{
cout <"Connect with error: " <return -1;
}
else
{
cout <"Connect successfully!" <char filebuf[MAX_LEN + 1]; //
// , , ,
while (true)
{
cout <"Ready to send file" <int len3 = strlen(argv[3]);
//
char filename[MAX_PATH];
int i = 0;
for (i = 0; i 3][i];
}
filename[i++] = '#';
//
iResult = send(ConnectSocket, filename, strlen(filename), 0);
if (iResult == SOCKET_ERROR)
{
cout <"Send Filename : " <" with error " <"
" <break;
}
//
int len;
FILE* fp;
if(fp = fopen(argv[3], "r"))
{
fseek(fp, 0, SEEK_END);
printf("%ld
", ftell(fp));
len = ftell(fp);
fclose(fp);
}
else
{
cout <"Error" <//
ifstream sourcefile(argv[3], ios::in | ios::binary);
int filelen = len;
int filelen_net = htonl(filelen);
//
cout <"Sending the length of file: " <"
" <char*)&filelen_net, 4, 0);
if (iResult == SOCKET_ERROR)
{
cout <"Send file length failed with error " <break;
}
//
cout <"Ready to send file!" <int left = filelen;
while (left>0)
{
if (left > MAX_LEN)
{
sourcefile.read(filebuf, MAX_LEN);
iResult = send(ConnectSocket, filebuf, MAX_LEN, 0);
if (iResult == SOCKET_ERROR)
{
cout <"Send file content failed with error " <"
" <break;
}
left -= MAX_LEN;
}
else
{
sourcefile.read(filebuf, left);
iResult = send(ConnectSocket, filebuf, left, 0);
left = 0;
if (iResult == SOCKET_ERROR)
{
cout <"Send file content failed with error " <"
" <break;
}
}
}
sourcefile.close();
if (left != 0)
{
cout <"Send file content failed with error " <"
" <cout <"Client Exit..." <break;
}
//
iResult = recv(ConnectSocket, Recvbuffer, sizeof(Recvbuffer), 0);
Recvbuffer[iResult] = '\0';
if (iResult == SOCKET_ERROR)
{
cout <"Failed to receive confirm from server!
" <break;
}
else if (strcmp(Recvbuffer, "OK\0") == 0)
{
cout <"Received confirm from server: " <"
Sending file succeed!
" <break;
}
}
closesocket(ConnectSocket);
WSACleanup();
system("pause");
return 0;
}
サービス側
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#pragma comment (lib,"ws2_32.lib")
#define PORT 4000
#define IP_ADDR "0.0.0.0"
#define MAX_LEN 100000
//
int recvn(SOCKET s, char *recvbuf, unsigned int fixedlen)
{
int iResult;
int cnt; //
cnt = fixedlen;
while (cnt > 0)
{
iResult = recv(s, recvbuf, cnt, 0);
if (iResult 0)
{
cout <"Receive failed with error :" <return -1;
}
if (iResult == 0)
{
cout <"Data is not as long as fixed. Connection closed" <return fixedlen - cnt;
}
recvbuf += iResult;
cnt -= iResult;
}
return fixedlen;
}
//
int recvvl(SOCKET s, char*filename)
{
int iResult;
long recvlen;
int len_tran;
char Recvb[MAX_LEN];
//
iResult = recv(s, (char*)&len_tran, 4, 0);
if (iResult != 4)
{
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else
{
cout <"Length data is not complete. Connection closed
" <return -1;
}
}
recvlen =ntohl( len_tran);
cout <"The length of file to receive is " <"
" <int left = recvlen;
while (left > 0)
{
if (left > MAX_LEN)
{
iResult = recvn(s, Recvb, MAX_LEN);
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else if (iResult == 0)
{
cout <"Receive data stopped. There "<" bytes unreceived" <break;
}
else
{
cout <"Receive partial data : " <" bytes" <else
{
iResult = recvn(s, Recvb, left);
if (iResult == -1)
{
cout <"Receive failed with error " <return -1;
}
else if (iResult ==0 )
{
cout <"Receive data stopped. There " <" bytes unreceived" <break;
}
else
{
cout <"Receive data : " <" bytes" <0;
}
}
}
if (left == 0)
{
cout <"Receive all the data
" <return recvlen;
}
// ,
struct my_para
{
SOCKET connect_socket;
struct sockaddr_in addrinfo;
};
//
DWORD WINAPI ClientThread(LPVOID lpparameter)
{
struct my_para information = *(struct my_para *)lpparameter;
int iResult = 0;
char RecvBuffer[MAX_LEN];
SOCKET ConnectSocket = information.connect_socket;
int filelength = 0;
char filename[MAX_PATH] = { 0 };
while (TRUE)
{
//
iResult = recv(ConnectSocket, RecvBuffer, sizeof(RecvBuffer), 0);
if (iResult == SOCKET_ERROR || iResult == 0)
{
cout <"Client(" <" : " <") Exited" <// ,continue , , closesocket
closesocket(ConnectSocket);
return -1;
}
// , ,
int i = 0;
for (i; RecvBuffer[i] != '#'; i++)
{
filename[i] = RecvBuffer[i];
}
filename[i] = '\0';
cout <"The file " <" is to receive!
" <//
cout <"Ready to receive file!
" <if (iResult == 0 || iResult == -1)
{
cout <"Send file failed !
" <continue;
}
// , OK
char returnmessage[] = "OK\0";
iResult = send(ConnectSocket, returnmessage, strlen(returnmessage), 0);
if (iResult == SOCKET_ERROR)
{
cout <"Return confirm message with error " <continue;
}
else
{
cout <"Return success!
" <return 0;
}
int main(int argc, char * argv[])
{
WSADATA ws;
SOCKET ServerSocket = INVALID_SOCKET, ClientSocket = INVALID_SOCKET;
struct sockaddr_in LocalAddr, ClientAddr;
int iResult = 0;
int Addrlen = 0;
HANDLE hThread = NULL;
//Initiate
iResult = WSAStartup(MAKEWORD(2, 2), &ws);
if (iResult != 0)
{
cout <"Initiate failed with error: " <return -1;
}
//create socket
ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ServerSocket == INVALID_SOCKET)
{
cout <"create socket failed with error: " <return -1;
}
LocalAddr.sin_family = AF_INET;
LocalAddr.sin_addr.s_addr = inet_addr(IP_ADDR);
LocalAddr.sin_port = htons(PORT);
memset(LocalAddr.sin_zero, 0x00, 8);
//bind socket
iResult = bind(ServerSocket, (struct sockaddr *)&LocalAddr, sizeof(LocalAddr));
if (iResult != 0)
{
cout <"Bind socket failed: " <return -1;
}
//listen
iResult = listen(ServerSocket, 10);
if (iResult != 0)
{
cout <"Listen socket failed with error: " <return -1;
}
cout <"Server is already setup!
" <while (TRUE)
{
Addrlen = sizeof(ClientAddr);
acc_sock = accept(ServerSocket, (struct sockaddr*)&ClientAddr, &Addrlen);
if (acc_sock 0)
{
cout <"Accept failed with error: " <break;
}
char *addr_temp = inet_ntoa(ClientAddr.sin_addr);
cout <"Client has already connected! (" <" : " <")
" <struct my_para temp;
temp.addrinfo = ClientAddr;
temp.connect_socket = acc_sock;
hThread = CreateThread(NULL, 0, ClientThread, (LPVOID)&temp, 0, NULL);
if (hThread == NULL)
{
cout <"Create Thread failed!" <break;
}
CloseHandle(hThread);
}
closesocket(ServerSocket);
closesocket(ClientSocket);
WSACleanup();
system("pause");
return 0;
}