关于TCP
TCP协议作为传输层另一常用协议,强调传输数据的正确性,而一些文件传输并不需要过分追求实时性,而想要确保收到的文件没有损坏,想象一下,你发表一篇论文如果采用不可靠(相对)的UDP协议,假如其中一个公式的一个符号丢失或改变都将影响整篇论文。所以,在面对一些重要文件传输时因选择TCP,而音乐,视频等可以接受一定的损坏,可能只是丢几帧,并不影响整体体验,采用代价更小的UDP更好,以下代码仅考虑TCP。
文件传输
文件传输无非是把被传输文件中所以数据拷贝到另一个空白文件当中,我们很多情况下并不知道需要下载的文件有多大,只能设定一个缓冲区去不断接收来自发送端的数据然后拷贝到空白文件之中。对于发送端而言能轻易知道什么时候文件读取完毕 (ret = read(fd,buf,size)) == 0 (read返回每次读到的字节数)时表示文件指针已经指向了数据末尾,无新数据可读了。但是对于接收端来说,并不清楚什么时候所有数据传输完成,只能一直循环等待对方的传输。代码表示为while((ret=read(conn_fd),buf,size) > 0); 但是当对方传输完成后,自己并不清楚是不是已经结束传输,只能阻塞等待读取缓冲区,所以我们需要一个办法告诉用户文件读取完成了。
告诉用户传输完成的两种方法
只有当接收端收到FIN包,此时read才会返回0,而实现此操作有两个方法;
1. 直接传输方直接关闭连接套接字,close(int fd);
2.int shutdown(int sockfd, int how);
how(linux)参数:SHUT_RD:断开输入流;
SHUT_WR:断开输出流;
SHUT_RDWR:断开I/O流;
此时套接字任然存在。
实现:
server端。
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
typedef struct{
char name[20]; //文件名
int i; //1为上传,2为下载,3为查看目录文件,4为退出。
}INFO; //保存客户端请求信息
int len_s = sizeof(struct sockaddr_in);
int len_c = sizeof(struct sockaddr_in);
int serv_fd; //套接字
void *thread_handler(void *); //线程操作,实现文件收发
void recv_file(int ,char *); //用户上传文件
void send_file(int ,char *); //用户下载文件
void show(int ); //给用户展示目录项
int main(int argc, char *argv[])
{
if( argc != 3){
printf("%s: <IP> <port>",argv[0]);
}
int clnt_fd; //连接套接字
int ret,i;
struct sockaddr_in serv_addr,clnt_addr;
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]); //终端第一个参数为IP地址
serv_addr.sin_port = htons(atoi(argv[2])); //终端第二个参数为端口号
serv_fd = socket(AF_INET,SOCK_STREAM,0); //采用流式套接字
if( serv_fd < 0){
perror("socket");
exit(0);
}
ret = bind(serv_fd,(struct sockaddr*)&serv_addr,len_s); //绑定

该博客介绍了如何使用Linux C语言基于TCP协议实现文件服务器。重点在于如何通过TCP确保文件传输的正确性,以及在文件传输完成后如何通知客户端。文章提到了两种通知客户端文件传输完成的方法,并给出了部分代码实现,包括server端和client端。虽然存在一些未解决的问题,如每次close()连接后只能执行一次操作,但整体项目展示了基本功能。
最低0.47元/天 解锁文章
2667





