TCP文件传输代码

【client.c】

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

enum Type{
	TYPE_REGIST,
	TYPE_LOGIN,
	TYPE_CHAT,
	TYPE_FILE_UPLOAD_REQUEST
};

typedef struct Pack{
	enum Type type;
	char name[20];
	char pswd[20];
	char filename[20];
	long filesize;
	char tarname[20];
	char text[1024];
}pack_t;

void* thread_main(void* arg){
	int client = *(int*)arg;
	while(1){
		pack_t pack = {0};
		int res = read(client, &pack, sizeof(pack));
		if(res == 0){break;}
		switch(pack.type){
    		case TYPE_REGIST:{
				printf("%s\n", pack.text);
       			break;
			}
    		case TYPE_LOGIN:{
				printf("%s\n", pack.text);
       			break;
			}
			case TYPE_CHAT:{
				printf("接收到消息:%s\n", pack.text);
				break;
			}
			case TYPE_FILE_UPLOAD_REQUEST:{
				char filename[128] = "./client_file_system/";
				// 获取文件名,方便打开文件
				strcat(filename, pack.filename);
				int fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0666);
				// 获取文件长度
				long filesize = pack.filesize;
				long readed_size = 0;
				
				//printf("接收到文件名和文件大小\n");
				while(1){
					pack_t filepack = {0};
					// 读取别的客户端发来的文件内容
					int res = read(client, &filepack, sizeof(filepack));
					if(res != sizeof(filepack)){
						printf("发生分包\n");
					}
					int size = strlen(filepack.text);
					write(fd, filepack.text, size);
					readed_size += size;
					if(readed_size >= filesize){
						close(fd);
						break;
					}
				}
				break;
			}
		}
	}
}

int main(int argc, const char *argv[])
{
	if(argc != 2){
		printf("请输入端口号\n");
		return 1;
	}
	int port = atoi(argv[1]);// 将字符串转换成int类型port
	int client = socket(AF_INET, SOCK_STREAM, 0);
	addr_in_t addr = {0};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("192.168.126.155");

	if(connect(client, (addr_t*)&addr, sizeof(addr)) == -1){
		perror("connect");
		return 1;
	}

	pthread_t id;
	pthread_create(&id, 0, thread_main, &client);
	pthread_detach(id);

	while(1){
		int ch = -1;
		printf("1:注册\n");
		printf("2:登录\n");
		printf("3:聊天\n");
		printf("4:发送文件\n");
		printf("0:退出\n");
		printf("请选择:");
		scanf("%d", &ch);
		while(getchar() != 10);
		switch(ch){
			case 1:{
				pack_t pack = {0};
				printf("请输入账号:");
				scanf("%s", pack.name);
				while(getchar()!=10);

				printf("请输入密码:");
				scanf("%s", pack.pswd);
				while(getchar() != 10);

				pack.type = TYPE_REGIST;
				write(client, &pack, sizeof(pack));
				break;
			}
			case 2:{
				pack_t pack = {0};
				printf("请输入账号:");
				scanf("%s", pack.name);
				while(getchar() != 10);

				printf("请输入密码:");
				scanf("%s", pack.pswd);
				while(getchar() != 10);

				pack.type = TYPE_LOGIN;
				write(client, &pack, sizeof(pack));
				break;
			}
			case 3:{
				pack_t pack = {0};
				pack.type = TYPE_CHAT;

				scanf("%s %s", pack.tarname, pack.text);
				printf("tarname = %19s\n", pack.tarname);
				while(getchar() != 10);
				write(client, &pack, sizeof(pack));
				break;
			}
			case 4:{
				pack_t pack = {0};
				pack.type = TYPE_FILE_UPLOAD_REQUEST;

				printf("请输入接受文件的用户名:");
				char tarname[20] = "";
				scanf("%19s", pack.tarname);
				strcpy(tarname, pack.tarname);
				while(getchar() != 10);

				printf("请输入想要发送的文件名:");
				scanf("%19s", pack.filename);
				while(getchar() != 10);
				int fd = open(pack.filename, O_RDONLY);
				if(fd == -1){
					printf("该文件不存在\n");
					break;
				}
				struct stat buf = {0};
				stat(pack.filename, &buf);
				pack.filesize = buf.st_size;
				write(client, &pack, sizeof(pack));
				
				while(1){
					pack_t pack = {0};
					pack.type = TYPE_FILE_UPLOAD_REQUEST;
					strcpy(pack.tarname, tarname);
					int res = read(fd, pack.text, 1023);
					if(res == 0){break;}
					write(client, &pack, sizeof(pack));
				}
				close(fd);
				break;
			}
			case 0:{
				break;
			}
		}
	}
	return 0;
}


【server.c】

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <sys/epoll.h>

typedef struct sockaddr_in addr_in_t;
typedef struct sockaddr addr_t;
typedef struct sockaddr_un addr_un_t;

enum Type{
    TYPE_REGIST,
    TYPE_LOGIN,
    TYPE_CHAT,
	TYPE_FILE_UPLOAD_REQUEST
};

typedef struct Pack{
	enum Type type;
	char name[20];
	char pswd[20];
	char filename[20];
	long filesize;
	char tarname[20];
	char text[1024];
}pack_t;

typedef struct User{
	char name[20];
	char pswd[20];
	int sock;
	int hasMsg;
	char msg[1024];
}user_t;

user_t user_arr[50] = {0};
int user_len = 0;

void read_data(int client);
void insert_user(user_t user);
int find_user(const char* username);

int main(int argc, const char *argv[])
{
	if(argc != 2){
		printf("请输入端口号\n");
		return 1;
	}

	int port = atoi(argv[1]);// 将字符串转换成int类型port

	// 创建服务器套接字
	int server = socket(AF_INET, SOCK_STREAM, 0);

	// 准备网络地址结构体:struct sockaddr_in
	addr_in_t addr = {0};
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr("0.0.0.0");

	// 为套接字绑定ip 和 port
	if(bind(server, (addr_t*)&addr, sizeof(addr)) == -1){
		perror("bind");
		return 1;
	}

	// 监听
	listen(server,10);
	
	// 创建监视列表
	int epfd = epoll_create1(EPOLL_CLOEXEC);

	// 将 0 和 server 存入监视列表 epfd 中
	struct epoll_event epoll_stdin = {
		.events = EPOLLIN,
		.data.fd = 0
	};

	struct epoll_event epoll_server = {
		.events = EPOLLIN,
		.data.fd = server
	};

	epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &epoll_stdin);
	epoll_ctl(epfd, EPOLL_CTL_ADD, server, &epoll_server);

	// 准备一个数组,用来存放所有激活的描述符
	struct epoll_event arr[50] = {0};

	while(1){
		int len = epoll_wait(epfd, arr, 50, -1);
		for(int i=0; i<len; i++){
			int fd = arr[i].data.fd; // 将激活了的描述符单独取出来
			if(fd == server){
				printf("有新客户端连接\n");
				int client = accept(server, 0, 0);

				struct epoll_event epoll_client = {
					.events = EPOLLIN,
					.data.fd = client
				};
				epoll_ctl(epfd, EPOLL_CTL_ADD, client, &epoll_client);
			}else if(fd == 0){
				char buf[64] = "";
				scanf("%63s", buf);
				while(getchar() != 10);
				printf("键盘输入数据:%s\n", buf);
			}else{
				read_data(fd);
			}
		}
	}
	return 0;
}

void insert_user(user_t user)
{
	user_arr[user_len] = user;
	user_len ++;
}

int find_user(const char* username)
{
	for(int i=0; i<user_len; i++){
		if(strcmp(username, user_arr[i].name) == 0){
			return i;
		}
	}
	return -1;
}

void read_data(int client)
{
	pack_t pack = {0};
	int res = read(client, &pack, sizeof(pack));
	switch(pack.type){
		case TYPE_REGIST:{
			int res = find_user(pack.name); // 判断用户发来的账号在数组中查询是否存在
			char* msg = NULL;
			if(res == -1){
				user_t user = {0};
				strcpy(user.name, pack.name);
				strcpy(user.pswd, pack.pswd);
				insert_user(user);
				msg = "注册成功";
			}else{
				msg = "该账号已存在";
			}
			strcpy(pack.text,msg);
			write(client, &pack, sizeof(pack));
			break;
		}
		case TYPE_LOGIN:{
			int res  = find_user(pack.name);
			char* msg = NULL;
			if(res == -1){
				msg = "该账号不存在";
			}else{
				user_t user = user_arr[res];
				if(strcmp(user.pswd, pack.pswd) == 0){
					msg = "登录成功";
					user_arr[res].sock = client;
					if(user_arr[res].hasMsg == 1){
						pack_t pack = {0};
						pack.type = TYPE_CHAT;
						strcpy(pack.text, user_arr[res].msg);
						write(client, &pack, sizeof(pack));
						user_arr[res].hasMsg = 0;
					}
				}else{	
					msg = "密码错误";
				}
			}
			strcpy(pack.text, msg);
			write(client, &pack, sizeof(pack));
			break;
		}
		case TYPE_CHAT:{
			char* msg = NULL;
			int res = find_user(pack.tarname);
			if(res == -1){
				msg = "该用户不存在";
				strcpy(pack.text, msg);
				write(client, &pack, sizeof(pack));
			}else{
				user_t user = user_arr[res];
				if(user.sock == 0){
					user_arr[res].hasMsg = 1;
					strcpy(user_arr[res].msg, pack.text);
				}else{
					// 用户存在并登录的状态
					int tarsock = user.sock;
					write(tarsock, &pack, sizeof(pack));
				}
			}
			break;
		}
		case TYPE_FILE_UPLOAD_REQUEST:{
			int res = find_user(pack.tarname);
			if(res == -1){
				// 没注册 今晚作业
				char* msg = "用户不存在"; //
				strcpy(pack.text, msg); //
				write(client, &pack, sizeof(pack)); //
			}else{
				if(user_arr[res].sock == 0){
					// 不在线 今晚作业
					user_arr[res].hasMsg = 1; //
					strcpy(user_arr[res].msg, pack.text); //
					char* msg = "用户不在线,文件上传请求已保存"; //
					strcpy(pack.text, msg); //
					write(client, &pack, sizeof(pack)); //
				}else{
					// 目标用户在线,直接将接收到的pack包转发给目标用户
					printf("转发文件中...\n");
					write(user_arr[res].sock, &pack, sizeof(pack));
				}
			}
			break;
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值