C语言基于socket的文件传输(可循环发送多个文件)

基本简介:

本次文件传输的实现主要是通过客户端向服务器发送下载请求,然后在服务器中找到对应的文件并打开文件,再继续向客户端传送文件,而客户端就在不停的接收。这是因为文件可能比较大,一个缓冲数组只能保存一部分文件内容,因此服务器得不断从文件中读取内容并发给客户端,而客户端得不停的循环接收。

但是在事先,得将相应要发送的文件(照片,音频,视频等)保存在服务器相应的目录下。而这个是不符合实际要求的,通常来讲,是应该将客户端1的文件发送给客户端2,而服务器仅仅只是起到一个中转站的作用,即文件应该事先保存在客户端1下。这里我们只是完成文件传输的相应功能就行了,就不在计较这些啦。因为只要你理解了这一块,可以根据自己的实际需要,在进行修改。

具体编译:

gcc server.c -o server -lpthread     //这是因为在服务器中加入了线程函数,所以编译的时候需要加上 -lpthread  。

gcc client.c -o client 

记住一定要先运行服务器,在运行客户端。在客户端运行的时候回提醒你输入服务器对应的pc ip,如实输入就行啦。如果是在本机pc上进行测试的话,也可以输入0.0.0.0   。


server.c:

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <pthread.h>

#define portnum 12345
#define FILE_SIZE 500 
#define BUFFER_SIZE 1024

void *net_thread(void * fd);

int main()
{
	//初始化套接字
	int server_fd=socket(AF_INET,SOCK_STREAM,0);
	if(-1==server_fd)
	{
		perror("socket");
		exit(1);
	}
	//绑定端口和ip;
	struct sockaddr_in server_addr;   //struct sockaddr_in为结构体类型 ,server_addr为定义的结构体   
	server_addr.sin_family=AF_INET;   //Internet地址族=AF_INET(IPv4协议) 
	server_addr.sin_port=htons(portnum);  //将主机字节序转化为网络字节序 ,portnum是端口号
	(server_addr.sin_addr).s_addr=htonl(INADDR_ANY);//IP地址
	if(-1==bind(server_fd,(struct sockaddr *)&server_addr,sizeof(server_addr)))  //套接字与端口绑定
	{
		perror("bind");
		exit(6);
	}
	//开启监听
	if(-1==listen(server_fd,5)) //5是最大连接数,指服务器最多连接5个用户
	{
		perror("listen");
		exit(7);
	}
	
	while(1)
	{
		struct sockaddr_in client_addr;
		int size=sizeof(client_addr);
		int new_fd=accept(server_fd,(struct sockaddr *)&client_addr,&size);  //server_fd服务器的socket描述字,&client_addr指向struct sockaddr *的指针,&size指向协议地址长度指针

		if(-1==new_fd)
		{
			perror("accept");
			continue;       //进行下一次循环
		}
		printf("accept client ip:%s:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
		//inet_ntoa将一个十进制网络字节序转换为点分十进制IP格式的字符串。
		
		printf("new_fd=%d\n",new_fd);
		
		// 打开文件,存入客户端的文件描述符
	    FILE *file_fp = fopen("01.file_fp", "w+"); 
        if(NULL == file_fp) 
        { 
             printf(" open 01.file_fp failure\n" ); 
             exit(1); 
        } 
	    else 
	    {
		     int a=new_fd;
		     fprintf(file_fp,"%d\n",new_fd);
		     fclose(file_fp);
	    }
			
		int pthread_id;
		int ret = pthread_create((pthread_t *)&pthread_id,NULL,net_thread,(void *)&new_fd);
		if(-1==ret)
		{
			perror("pthread_create");
			close(new_fd);
			continue;
		}
		
	}
	close(server_fd);
	return 0;

}



void *net_thread(void * fd)
{
	pthread_detach(pthread_self()); //线程分离
	int new_fd=*((int *)fd);
	int file2_fp;
	
	while(1)
	{
		// recv函数接收数据到缓冲区buffer中 
        char buffer[BUFFER_SIZE];
        memset( buffer,0, sizeof(buffer) );		
        if(read(new_fd, buffer, sizeof(buffer)) < 0) 
        { 
           perror("Server Recieve Data Failed:"); 
           break; 
        } 
		
        // 然后从buffer(缓冲区)拷贝到file_name中 
        char file_name[FILE_SIZE]; 
		memset( file_name,0, sizeof(file_name) );	
        strncpy(file_name, buffer, strlen(buffer)>FILE_SIZE?FILE_SIZE:strlen(buffer)); 
		memset( buffer,0, sizeof(buffer) );
        printf("%s\n", file_name); 
		
		if( strcmp(file_name,"null")==0 )
	    {
		   break;
		   close(new_fd);
	    }
		
		  // 打开文件并读取文件数据 
         file2_fp = open(file_name,O_RDONLY,0777); 
         if(file2_fp<0) 
         { 
            printf("File:%s Not Found\n", file_name); 
         } 
         else 
         { 
            int length = 0; 
			memset( buffer,0, sizeof(buffer) );
            // 每读取一段数据,便将其发送给客户端,循环直到文件读完为止 
            while( (length = read(file2_fp, buffer, sizeof(buffer))) > 0  )    
            {   
                if( write(new_fd, buffer, length) < 0) 
                { 
                    printf("Send File:%s Failed.\n", file_name); 
                    break; 
                } 
                memset( buffer,0, sizeof(buffer) );
            } 
              // 关闭文件 
              close(file2_fp); 
              printf("File:%s Transfer Successful!\n", file_name); 
         }   
	}
	close(new_fd);
}

client.c:

#include <stdio.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>

#define portnum 12345
#define FILE_SIZE 500 
#define BUFFER_SIZE 1024

int sendfile(int sockfd);

int main()
{
	char name[30]={0};
	printf("请输入服务器的主机名或者ip\n");
	scanf("%s",name);
	struct hostent *h;
	//获取服务器信息
	h=gethostbyname(name);
	if(NULL==h)
	{
		perror("geyhostbyname");
		exit(1);
	}
	//初始化套接字
	int sockfd=socket(AF_INET,SOCK_STREAM,0);
	if(-1==sockfd)
	{
		perror("socket");
		exit(2);
	}
	struct sockaddr_in server_addr;
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(portnum);
	server_addr.sin_addr=*((struct in_addr *)h->h_addr_list[0]);
	if(-1==connect(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)))
	{
		perror("connect");
		exit(3);
	}
	
	while(1)
	{
		
	sendfile(sockfd);

    }
	return 0;
	
}
int sendfile(int sockfd)
{
    // 输入文件名 并放到缓冲区buffer中等待发送 
	int file_fp;
    char file_name[FILE_SIZE];  
	memset( file_name,0, sizeof(file_name) );
    printf("Please Input File Name On Server:   "); 
    scanf("%s", file_name); 
   
    char buffer[BUFFER_SIZE]; 
    memset( buffer,0, sizeof(buffer) );
    strncpy(buffer, file_name, strlen(file_name)>sizeof(buffer)?sizeof(buffer):strlen(file_name)); 
     
    // 向服务器发送buffer中的数据 
    if(write(sockfd, buffer, sizeof(buffer)) < 0) 
    { 
       perror("Send File Name Failed:"); 
       exit(1); 
    } 
	
	if( strcmp(file_name,"null")==0 )
	{
		exit(1);
		close(sockfd);
	}	
	 // 打开文件,准备写入 
     file_fp = open(file_name,O_CREAT|O_RDWR,0777); 
     if( file_fp<0 ) 
     { 
         printf("File:\t%s Can Not Open To Write\n", file_name); 
         exit(1); 
     } 
   
     // 从服务器接收数据到buffer中 
     // 每接收一段数据,便将其写入文件中,循环直到文件接收完并写完为止 
    int length = 0; 
	memset( buffer,0, sizeof(buffer) );
   
    while((length = read(sockfd, buffer, sizeof(buffer))) > 0) 
    { 
        if( write( file_fp, buffer, length ) < length) 
        { 
            printf("File:\t%s Write Failed\n", file_name); 
            break; 
        } 
		if(length < sizeof(buffer))
		{
			break;
		}
        memset( buffer,0, sizeof(buffer) );
    } 
	 
	// 接收成功后,关闭文件,关闭socket 
     printf("Receive File:\t%s From Server IP Successful!\n", file_name); 
     close(file_fp); 	
}

  • 17
    点赞
  • 197
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: 好的,我来为您解答。 基于 TCP 协议的文件接收程序可以使用 C 语言实现。具体步骤如下: 1. 包含必要的头文件: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> ``` 2. 创建 socket: ``` int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket error"); exit(1); } ``` 3. 设置服务器地址: ``` struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); // PORT 是服务器监听的端口号 servaddr.sin_addr.s_addr = inet_addr(SERVER_IP); // SERVER_IP 是服务器的 IP 地址 ``` 4. 连接服务器: ``` if (connect(sockfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { perror("connect error"); exit(1); } ``` 5. 接收数据: ``` char buf[BUFSIZ]; // BUFSIZ 是 C 编译器中定义的常量,表示缓冲区大小 int n = recv(sockfd, buf, BUFSIZ, 0); if (n < 0) { perror("recv error"); exit(1); } ``` 6. 将数据写入文件: ``` FILE *fp = fopen(FILENAME, "w"); // FILENAME 是文件名 if (fp == NULL) { perror("fopen error"); exit(1); } fwrite(buf, 1, n, fp); fclose(fp); ``` 7. 关闭 socket: ``` close(sockfd); ``` 这是基于 TCP 协议的文件接收程序的大体流程。 ### 回答2: 基于TCP协议的文件接收程序可以使用C语言编写。在C语言中,我们可以使用套接字(socket)函数来创建一个TCP套接字,并使用bind函数将套接字绑定到一个特定的IP地址和端口号。 接下来,我们可以使用listen函数将套接字设置为监听模式,等待客户端的连接请求。一旦接受到连接请求,我们可以使用accept函数来接受连接,并返回一个新的套接字,可以用来进行数据传输。 在接受连接后,我们可以使用recv函数来接收客户端发送过来的文件数据。由于TCP是面向流的协议,数据可能会被分成多个TCP片段进行传输,因此我们需要循环调用recv函数来接收所有的数据,直到接收完整个文件为止。 接收到数据后,我们可以使用文件操作函数(如fopen和fwrite)来将数据写入到一个文件中。在写入文件之前,需要根据文件名和路径创建一个新文件。 在接收完文件后,关闭套接字,并释放相关资源。 以下是一个简单的基于TCP协议的文件接收程序的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #define BUFFER_SIZE 1024 int main() { // 创建TCP套接字 int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { perror("socket"); exit(EXIT_FAILURE); } // 绑定套接字到IP地址和端口号 struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(12345); server_addr.sin_addr.s_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) { perror("bind"); exit(EXIT_FAILURE); } // 设置监听模式,等待连接请求 if (listen(sockfd, 5) == -1) { perror("listen"); exit(EXIT_FAILURE); } // 接受连接请求,返回一个新的套接字 struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int new_sockfd = accept(sockfd, (struct sockaddr*)&client_addr, &client_addr_len); if (new_sockfd == -1) { perror("accept"); exit(EXIT_FAILURE); } // 接收文件数据并写入文件 FILE *fp = fopen("received_file", "wb"); if (fp == NULL) { perror("fopen"); exit(EXIT_FAILURE); } char buffer[BUFFER_SIZE]; int recv_bytes; while ((recv_bytes = recv(new_sockfd, buffer, BUFFER_SIZE, 0)) > 0) { fwrite(buffer, sizeof(char), recv_bytes, fp); } if (recv_bytes == -1) { perror("recv"); exit(EXIT_FAILURE); } // 关闭套接字和文件 fclose(fp); close(new_sockfd); close(sockfd); return 0; } ``` 以上程序将监听本地12345端口,接受客户端的连接请求,并将接收到的文件数据依次写入到名为"received_file"的文件中。 ### 回答3: 基于TCP协议,可以使用C语言编写一个文件接收程序。下面是一个简单的实现步骤: 1. 引入必要的头文件: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> ``` 2. 创建socket: ```c int server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { printf("创建socket失败\n"); exit(1); } ``` 3. 绑定server端口: ```c struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_addr.sin_port = htons(PORT); // PORT是指定的服务器端口号 if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) { printf("绑定端口失败\n"); exit(1); } ``` 4. 监听连接请求: ```c if (listen(server_socket, 5) == -1) { printf("监听失败\n"); exit(1); } ``` 5. 接收客户端连接请求: ```c struct sockaddr_in client_addr; socklen_t client_addr_len = sizeof(client_addr); int client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len); if (client_socket == -1) { printf("接受连接失败\n"); exit(1); } ``` 6. 接收文件并写入磁盘: ```c FILE *fp = fopen("received_file", "wb"); // received_file为接收到的文件名 if (fp == NULL) { printf("创建文件失败\n"); exit(1); } char buffer[1024]; int bytes_received; while ((bytes_received = recv(client_socket, buffer, sizeof(buffer), 0)) > 0) { fwrite(buffer, sizeof(char), bytes_received, fp); } fclose(fp); ``` 7. 关闭连接和socket: ```c close(client_socket); close(server_socket); ``` 这样,文件接收程序就完成了。请注意,以上只是一个简单的示例,实际的应用中还需考虑错误处理、数据完整性的校验等。同时,文件传输过程中要确保server和client的协议一致,例如文件名、接收缓冲区大小等。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值