TCP文件传输的设计与实现

本实验是掌握 Windows 环境下使用 Socket 开发的方法 ,利用tcp实现文件的传输。

算法思想: 首先服务端加载套接字库然后调用socket函数创建一个socket,调用bind函数将地址与端口号绑定,然后listen监听来自客户端请求。客户端建立socket,利用connect函数将套接字与服务器相连接,连接成功则返回连接成功反之返回连接失败。然后客户端先获取待发送文件的文件名(包含文件路径)以及文件长度,发送给服务端,服务端接收到文件名和文件长度之后为其创建新的文件保存路径和数据缓冲区。之后客户端建立和文件大小一样的缓冲区,利用fread函数将文件内容读入缓冲区再将缓冲区内容利用send函数发送给服务端,服务端利用recv函数将接收的文件的数据写入缓冲区,最后利用fwrite函数依次将数据缓冲区的数据写入新创建的文件中。

程序流程图:

代码: 

Server
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <WinSock2.h> 
 
#define SERVER_IP "127.0.0.1" 
#define B_SIZE 1024 
#define FILE_SIZE 512
#pragma comment(lib, "WS2_32") 
  
int main() 
{ 
  WSADATA wsdt; 
  WORD skVer = MAKEWORD(2, 2); 
  if(WSAStartup(skVer, &wsdt) != 0) 
  { 
    printf("端口初始失败!"); 
    return 0;
  } 
  // 创建socket 
  SOCKET s_skt = socket(AF_INET, SOCK_STREAM, 0); 
    if (s_skt == SOCKET_ERROR) 
    { 
      printf("创建socket失败!"); 
      return 0;
    } 
  // 声明并初始化一个服务端(本地)的地址结构 
  sockaddr_in addr_ser; 
  addr_ser.sin_family = AF_INET; 
  addr_ser.sin_addr.S_un.S_addr = INADDR_ANY; 
  addr_ser.sin_port = htons(8087);  
  //绑定socket和服务端(本地)地址 
  if (bind(s_skt, (LPSOCKADDR)&addr_ser, sizeof(addr_ser))) 
  { 
    printf("绑定失败!"); 
    return 0; 
  } 
  //监听 
  if (SOCKET_ERROR==listen(s_skt, 10)) 
  { 
    printf("监听失败!"); 
    return 0; 
  }  
  for(;;) { 
    printf("监听中...\n"); 
    sockaddr_in addr_cli; 
    int addr_cli_len = sizeof(addr_cli); 
	SOCKET s_Socket = accept(s_skt, (sockaddr *)&addr_cli, &addr_cli_len); 
    if (s_Socket==SOCKET_ERROR) 
    { 
      printf("接收失败!"); 
      break; 
    } 
    char server_buffer[B_SIZE]; 
    memset(server_buffer, 0, B_SIZE); //初始化
    if (recv(s_Socket, server_buffer, B_SIZE, 0) < 0) 
    { 
      printf("服务端接收数据失败!"); 
      break; 
    } 
    char recvfile[FILE_SIZE+1]; 
	char str[20];
    memset(recvfile, 0, FILE_SIZE+1); 
	if(strlen(server_buffer)>FILE_SIZE){
		strncpy(recvfile,server_buffer,FILE_SIZE);
	}else{
		strncpy(recvfile,server_buffer,strlen(server_buffer));
	}
    printf("%s\n", recvfile);
    printf("请输入文件保存路径:");
	gets(str);
    FILE * fp = fopen(str, "wb");
	if(fp==NULL){
		printf("文件打开失败!");
		return 0;
	}
    memset(server_buffer, 0, B_SIZE); 
	int i=0;
    for(;;){
		i+=B_SIZE;
		recv(s_Socket, server_buffer, B_SIZE+1,0);
		fwrite(server_buffer, 1, B_SIZE, fp);
		if(i>=ftell(fp)){
			printf("文件接收完毕!\n");
			fclose(fp); 
			break; 
        } 
      } 
	fclose(fp); 
    printf("文件: %传输成功!\n", recvfile); 
    closesocket(s_Socket); 
  } 
  
  closesocket(s_skt); 
  //释放winsock库 
  WSACleanup(); 
  return 0; 
} 

Client:
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <WinSock2.h> 
  
#define SERVER_IP "127.0.0.1" 
#define B_SIZE 1024 
#define FILE_MAX_SIZE 512
#pragma comment(lib, "WS2_32") 
  
int main() 
{ 
   // 初始化socket dll 
  WSADATA wsdt; 
  WORD skVer = MAKEWORD(2, 2); 
  if(WSAStartup(skVer, &wsdt) != 0) 
  { 
    printf("端口初始失败!"); 
    return 0;
  } 
  // 创建socket 
  SOCKET c_Socket = socket(AF_INET, SOCK_STREAM, 0);
    if (c_Socket==SOCKET_ERROR ) 
    { 
      printf("创建socket失败!"); 
      return 0;
    } 
  //指定服务端的地址 
  sockaddr_in addr_ser; 
  addr_ser.sin_family = AF_INET; 
  addr_ser.sin_addr.S_un.S_addr = inet_addr(SERVER_IP); 
  addr_ser.sin_port = htons(8087); 
  
  if (SOCKET_ERROR ==connect(c_Socket, (LPSOCKADDR)&addr_ser, sizeof(addr_ser))) 
  { 
    printf("连接失败!\n"); 
	return 0;
  } 
  //输入文件名 
  char sendfile[FILE_MAX_SIZE+1]; 
  memset(sendfile, 0, FILE_MAX_SIZE+1); 
  printf("请输入要发送的文件名: "); 
  scanf("%s", &sendfile); 
  
  char client_buffer[B_SIZE]; 
  memset(client_buffer, 0, B_SIZE); 
  if(strlen(client_buffer)>FILE_MAX_SIZE){
		strncpy(client_buffer,sendfile,B_SIZE);
	}else{
		strncpy(client_buffer,sendfile,strlen(sendfile));
	}
  if(send(c_Socket, client_buffer, B_SIZE, 0) < 0) 
  { 
    printf("文件名发送失败!\n"); 
    return 0; 
  } 
  //打开文件
  FILE * fp = fopen(sendfile, "rb");  
  if(NULL == fp) 
  { 
    printf("文件: %s 不能打开\n", sendfile);
    return 0;
  } 
  else
  { 
    memset(client_buffer, 0, B_SIZE); 
	int i=0;
    while (!feof(fp)) 
    { 
		fread(client_buffer, 1, B_SIZE, fp);		
		i+=B_SIZE;
		if(i<ftell(fp)){
		    send(c_Socket, client_buffer, B_SIZE+1, 0);
		}else{
			send(c_Socket, client_buffer,ftell(fp)+B_SIZE-i+1, 0);
			closesocket(c_Socket);
			//释放winsock库 
			WSACleanup(); 
		}
    } 
	fclose(fp); 
  }
	printf("文件发送完毕!");
	system("pause"); 
	return 0;
} 

结果截图:

 

其中1.txt中内容是要发送的文件内容,2.txt用于接收文件,文件名还有文件保存路径可改。

 

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值