1. 程式人生 > >Windows Socket程式設計之UDP實現大檔案的傳輸

Windows Socket程式設計之UDP實現大檔案的傳輸

前言:

本文實現以下功能:

在客戶端,使用者選擇本地的某個檔案,併發送到伺服器端。
在伺服器端,接收客戶端傳輸的資料流,並按IP 地址儲存在伺服器端(文
件名重複的,可以覆蓋)。
如果傳輸過程中伺服器端發現客戶端斷開,伺服器端應刪除檔案,並在螢幕
上提示,如“IP:1.2.3.4 發來abcd.txt 檔案過程中失去連線。”。如果客戶端發
現伺服器端不工作,客戶端應有提示“伺服器1.2.3.5:62345 失去連線”。

一、UDP傳輸流程圖


二、程式碼實現

1.1.FileHelper用來進行與檔案相關的操作

#include<stdio.h>
#include<stdlib.h>
#include <WINSOCK2.H>
#include <STDIO.H>
#pragma  comment(lib,"ws2_32.lib")

class FileHelper
{
private:
	FILE *f;
	char path_buffer[_MAX_PATH];
	char drive[_MAX_DRIVE];
	char dir[_MAX_DIR];
	char fname[_MAX_FNAME];
	char ext[_MAX_EXT];

public:
	FILE * selectfile()
	{
		printf("請輸入要傳送的檔名\n");
		scanf("%s",path_buffer);

		if (f=fopen(path_buffer,"rb"))
		{
			printf("檔案開啟成功\n");
			return f;
		}
		else
		{
			printf("檔案不存在,請重新輸入\n");
			return selectfile();
		}
	}

	char * getFileName()
	{
		_splitpath(path_buffer, drive, dir, fname, ext);
		return strcat(fname, ext);
	}
	FILE * createFile(char *name)
	{
		remove(name);
		if (f = fopen(name, "ab"))
		{
			printf("檔案建立成功\n");

		}
		else
		{
			printf("檔案建立失敗\n");
		}
		return f;
	}

	bool createDir(char *dir)
	{
		char head[MAX_PATH] = "md ";
		return system(strcat(head, dir));
	}





};

2.Client端
#pragma comment(lib,"Ws2_32.lib")

#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdio.h>
#include<Windows.h>

#include"FileHelper.h"

int main()
{

	WORD wVersionRequested;
	WSADATA wsaData;
	char sendData[BUFSIZ]="ÄãºÃ£¡\n";
	char beginData[BUFSIZ]="Begin\n";
	char overData[BUFSIZ]="Over\n";
	char Filename[BUFSIZ]={};
	FileHelper fh;
	int err;
	wVersionRequested = MAKEWORD(2, 2);

	err = WSAStartup(wVersionRequested, &wsaData);
	if (err != 0) {
		/* Tell the user that we could not find a usable */
		/* Winsock DLL.                                  */
		printf("WSAStartup failed with error: %d\n", err);
		return 1;
	}

	if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
		/* Tell the user that we could not find a usable */
		/* WinSock DLL.                                  */
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return 1;
	}

	SOCKADDR_IN addrServ;
	addrServ.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
	addrServ.sin_family=AF_INET;
	addrServ.sin_port=htons(4999);
	while (true)
	{
		SOCKET socketClient=socket(AF_INET,SOCK_DGRAM,0);
		FILE *f=fh.selectfile();
		sendto(socketClient,beginData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
		strcpy(Filename,fh.getFileName());
		sendto(socketClient,Filename,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
		int count=0;
		int sum=0;
		while ((count=fread(sendData,1,BUFSIZ,f))>0)
		{
			Sleep(1);
			printf("%d\n",sum+=count);
			sendto(socketClient,sendData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
		}
		sendto(socketClient,overData,BUFSIZ,0,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
		closesocket(socketClient);
	}
	WSACleanup();
	return 0;

}

3.Servet端

#pragma comment(lib,"Ws2_32.lib")
#include<WinSock2.h>
#include<WS2tcpip.h>
#include<stdio.h>
#include<Windows.h>
#include "FileHelper.h"

int main()
{
	WORD wVersionRequested;
	WSADATA wsaData;

	FileHelper fh;
	int err;
	wVersionRequested=MAKEWORD(2,2);
	err=WSAStartup(wVersionRequested,&wsaData);
	if (err!=0)
	{
		printf("WSAStartup failed with error:%d\n",err);
		return -1;
	}
	if (LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)
	{
		printf("Could not find a usable version of Winsock.dll\n");
		WSACleanup();
		return -1;
	}
	SOCKET socketServer=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
	SOCKADDR_IN addrServ;
	addrServ.sin_addr.S_un.S_addr=htonl(INADDR_ANY);//指定0.0.0.0地址,表示任意地址
	addrServ.sin_family=AF_INET;//表示IPv4的套接字型別
	addrServ.sin_port=htons(4999);
	bind(socketServer,(SOCKADDR*)&addrServ,sizeof(SOCKADDR));
	SOCKADDR_IN addrClient;
	int length=sizeof(SOCKADDR);
	char recvBuf[BUFSIZ]={};
	int rev=0;
	while (true)
	{
		DWORD TIME_OUT=10;
		char sendData[BUFSIZ]="你好!\n";
		char beginData[BUFSIZ]="Begin\n";
		char overData[BUFSIZ]="Over\n";
		char Filename[BUFSIZ]={};
		char ClientAddr[BUFSIZ]={};
		char FromName[BUFSIZ]={};
		FILE *f=NULL;
		if(err=setsockopt(socketServer,SOL_SOCKET,SO_SNDTIMEO,(char *)&TIME_OUT,sizeof(TIME_OUT)))
		{
			printf("失敗!\n");
		};
		printf("%d\n",err);
		recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length);
		if (strcmp(recvBuf,beginData)==0)
		{

			recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length);
			strcpy(ClientAddr,inet_ntoa(addrClient.sin_addr));
			strcpy(FromName,recvBuf);
			fh.createDir(ClientAddr);
			strcpy(Filename,ClientAddr);
			strcat(Filename,"\\");
			strcat(Filename,recvBuf);
			f=fh.createFile(Filename);

		}
		int sum=0;
		while((rev=recvfrom(socketServer,recvBuf,BUFSIZ,0,(SOCKADDR*)&addrClient,&length))>0)
		{
			if (strcmp(overData,recvBuf)==0)
			{
				printf("檔案%s傳輸成功!\n",FromName);
				fclose(f);
				break;
			}
		//	printf(recvBuf);
			fwrite(recvBuf,1,rev,f);
			printf("%db\n",sum+=rev);
		}

		if (rev<0||strcmp(overData,recvBuf)!=0)
		{
			printf("IP:%s發來的%s傳輸過程中失去連線\n",addrClient,FromName);
			fclose(f);
			remove(Filename);
		}

	}

	closesocket(socketServer);
	WSACleanup();
	return 0;

}