大禹123 的学生作业:
debug.h
#ifndef _DEBUG_H_
#define _DEBUG_H_
/*
__FILE__:输出文件名
__FUNCTION__:输出函数名
__LINE__:输出行号
}while:括号要与while连接在一起
*/
#define DEBUG_INFO(args...) do{ \
char b__[1024];\
sprintf(b__,args);\
fprintf(stderr,"[%s,%s,%d] : %s", __FILE__ , __FUNCTION__ ,__LINE__ ,b__); \
}while(0)
#endif
tcp_socket.h
#ifndef __TCP_SOCKET_H_
#define __TCP_SOCKET_H_
#include
#include
#include
#include /* See NOTES */
#include
#include
#include
#include
// 创建并初始化 tcp 服务器 socket
extern int create_tcp_server_socket(const char *ip,unsigned short port);
// 用于创建tcp客户端连接
extern int create_tcp_client_socket(const char *server_ip,unsigned short server_port);
//等待与客户端连接
extern int wait_for_connect(int sockfd, struct sockaddr_in* client_addr);
//显示连接客户端的地址信息
extern void show_tcp_network_addr(struct sockaddr_in *sockaddr);
//发送数据
extern ssize_t tcp_send_pack(int sockfd, const void *buf, size_t len);
//接收数据
extern ssize_t tcp_recv_pack(int sockfd, void *buf, size_t len);
#endif
tcp_socket.c
#include "tcp_socket.h"
#include "debug.h"
#define BACKLOG 10
int create_tcp_server_socket(const char *ip,unsigned short port)
{
int sfd;
int ret;
struct sockaddr_in server_addr;
socklen_t len = sizeof(struct sockaddr_in);
//1、创建套接字
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
DEBUG_INFO("[ERROR] socket:%s\n", strerror(errno));
return -1;
}
bzero(&server_addr, len);
//地址族/协议族 与socket函数第一个参数相同
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = inet_addr(ip);
//2、绑定ip,端口号
ret = bind(sfd, (const struct sockaddr *) &server_addr, len);
if(ret == -1)
{
DEBUG_INFO("[ERROR] bind():%s\n", strerror(errno));
return -1;
}
//3、设置套接字为监听状态,建立监听队列,如果服务端处理不过来的话,会把客户端连接请求缓存在监听队列里,如果超过最大队列数量,那么会被拒绝连接
ret = listen(sfd, BACKLOG);
if(ret == -1)
{
DEBUG_INFO("[ERROR] listen():%s\n", strerror(errno));
return -1;
}
return sfd;
}
int create_tcp_client_socket(const char *server_ip,unsigned short server_port)
{
int sfd;
int ret;
struct sockaddr_in server_addr;
//1、创建套接字
sfd = socket(AF_INET, SOCK_STREAM, 0);
if(sfd == -1)
{
DEBUG_INFO("[ERROR] socket():%s\n", strerror(errno));
return -1;
}
bzero(&server_addr, sizeof(struct sockaddr_in));
//地址族/协议族 与socket函数第一个参数相同
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(server_port);
server_addr.sin_addr.s_addr = inet_addr(server_ip);
ret = connect(sfd, (const struct sockaddr *) &server_addr, sizeof(struct sockaddr_in));
if(ret == -1)
{
DEBUG_INFO("[ERROR] connect():%s\n", strerror(errno));
return -1;
}
return sfd;
}
int wait_for_connect(int sockfd, struct sockaddr_in* client_addr)
{
int cfd;
socklen_t len = sizeof(struct sockaddr_in);
cfd = accept(sockfd, (struct sockaddr *)client_addr, &len);
if(cfd == -1)
{
DEBUG_INFO("[ERROR] accept():%s\n", strerror(errno));
return -1;
}
return cfd;
}
void show_tcp_network_addr(struct sockaddr_in *sockaddr)
{
printf("ip:%s prot:%d\n",inet_ntoa(sockaddr->sin_addr), ntohs(sockaddr->sin_port));
}
//发送数据
ssize_t tcp_send_pack(int sockfd, const void *buf, size_t len)
{
return send(sockfd, buf, len, 0);
}
//接收数据
ssize_t tcp_recv_pack(int sockfd, void *buf, size_t len)
{
return recv(sockfd, buf, len, 0);
}
file_transfer.h
#ifndef __FILE_TRANSFER_H_
#define __FILE_TRANSFER_H_
#include "tcp_socket.h"
#include
#include
#include
#define FILENAME_SIZE 256
enum TRANSFER_TYPE{
UPLOAD = 1,
DOWNLOAD
};
enum FILE_STATUS{
EXIST = 1,
NO_EXIST,
UNKNOWN
};
// |file protocol head| file data|
typedef struct file_protocol{
size_t filesize;
char filename[FILENAME_SIZE];
int transfer_type;
int file_is_exist;
}file_protocol_t;
//接收协议头信息
extern int recv_protocol_head(int cfd, file_protocol_t *p_head);
extern int recv_filedata(int cfd, const char *filename, ssize_t targetsize);
extern int reply_to_client(int cfd, file_protocol_t *p_head);
//服务器接收客户端上传的文件协议头与文件数据
extern int recv_client_file_transfer(int cfd);
//客户端发送协议头信息给服务器
extern int send_protocol_head(const char *filename, int sockfd, int transfer_type);
//接收服务器给客户端的答复
extern int recv_reply_server(int sfd, file_protocol_t *p_head);
//客户端发送文件数据给服务端
extern int client_upload_file(const char *filename, int sockfd);
//客户端从服务端下载文件
extern int client_down_file(const char *filename, int sockfd);
#endif
file_transfer.c
#include "file_transfer.h"
#include "debug.h"
int recv_protocol_head(int cfd, file_protocol_t *p_head)
{
ssize_t rbytes = 0;
ssize_t total_received = 0;
int len = sizeof(file_protocol_t);
char *buffer = (char *)p_head;
while (1)
{
rbytes = tcp_recv_pack(cfd, buffer + total_received, len - total_received);
if(rbytes == -1)
{
DEBUG_INFO("[ERROR]:%s\n",strerror(errno));
return -1;
}else if(rbytes == 0)
{
DEBUG_INFO("[INFO]:the client has been shutdown.\n");
break;
}else if(rbytes > 0)
{
total_received +=rbytes;
if(total_received == len)
{
break;
}
}
}
if(total_received != len)
{
DEBUG_INFO("[ERROR]:failed to recevied data.\n");
return -1;
}
return 0;
}
int recv_filedata(int cfd, const char *filename, ssize_t targetsize)
{
/*
O_WRONLY 只写
O_CREAT 没有就创建文件
O_TRUNC 有的话文件清零
0644 文件所有者:读写 文件所在组:读 其他用户:读
*/
int fd;
ssize_t rbytes = 0, wbytes = 0, file_size = 0;
char buffer[1024] = {0};
//1、打开文件
fd = open(filename, O_WRONLY | O_CREAT |O_TRUNC, 0644);
if(fd == -1)
{
DEBUG_INFO("[ERROR]:fail to open: %s\n",strerror(errno));
return -1;
}
//2、接收文件数据并写入本地文件中
while(1)
{
rbytes = tcp_recv_pack(cfd, buffer, sizeof(buffer));
if(rbytes == -1)
{
DEBUG_INFO("[ERROR]:fail to tcp_recv_pack: %s\n",strerror(errno));
return -1;
}else if(rbytes == 0)
{
//表示客户端断开连接
DEBUG_INFO("[INFO]:the client has been shutdown.\n");
break;
}else if(rbytes > 0)
{
wbytes = write(fd, buffer, rbytes);
if(wbytes == -1)
{
DEBUG_INFO("[ERROR]:fail to write: %s\n",strerror(errno));
return -1;
}
file_size +=rbytes;
if(file_size == targetsize)
{
break;
}
}
}
close(fd);
return file_size;
}
int reply_to_client(int cfd, file_protocol_t *p_head)
{
int fd, ret;
int filesize;
ssize_t rbytes = 0, sbytes = 0;
int upload_size = 0;
char buffer[1024] = {0};
fd = open(p_head->filename, O_RDONLY);
if(fd == -1)
{
p_head->file_is_exist = NO_EXIST;
DEBUG_INFO("[ERROR]:fail to open: %s\n",strerror(errno));
}else{
filesize = lseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET);
p_head->file_is_exist = EXIST;
p_head->filesize = filesize;
}
ret = tcp_send_pack(cfd, p_head, sizeof(file_protocol_t));
if(ret != sizeof(file_protocol_t))
{
DEBUG_INFO("[ERROR]:fail to tcp_send_pack: %s\n",strerror(errno));
return -1;
}
if(fd == -1) return -1;
while(1)
{
bzero(buffer, sizeof(buffer));
rbytes = read(fd, buffer, sizeof(buffer));
if(rbytes == -1)
{
DEBUG_INFO("[ERROR]:fail to read: %s\n",strerror(errno));
return -1;
}else if(rbytes == 0)
{
//表示读到文件尾了
break;
}
sbytes = tcp_send_pack(cfd, buffer, rbytes);
if(sbytes != rbytes)
{
DEBUG_INFO("[ERROR]:fail to tcp_send_pack: %s\n",strerror(errno));
return -1;
}
upload_size += sbytes;
}
return 0;
}
int recv_client_file_transfer(int cfd)
{
int ret, recvsize = 0;
file_protocol_t head;
bzero(&head, sizeof(file_protocol_t));
// 1、接收协议头信息
ret = recv_protocol_head(cfd, &head);
if(ret == -1) return -1;
if(head.transfer_type == DOWNLOAD)
{
//给客户端发送数据
ret = reply_to_client(cfd, &head);
return ret;
}else{
// 接收文件数据
recvsize = recv_filedata(cfd, head.filename, head.filesize);
printf("recvsize:%d\n", recvsize);
return recvsize;
}
}
int send_protocol_head(const char *filename, int sockfd, int transfer_type)
{
int fd, ret;
int filesize;
file_protocol_t head;
bzero(&head, sizeof(file_protocol_t));
//协议头信息: filename + filesize
head.transfer_type = transfer_type;
if(head.transfer_type == DOWNLOAD){
head.file_is_exist = UNKNOWN;
head.filesize = 0;
strcpy(head.filename, filename);
ret = tcp_send_pack(sockfd, &head, sizeof(head));
if(ret != sizeof(file_protocol_t))
{
DEBUG_INFO("[ERROR]:fail to tcp_send_pack: %s\n",strerror(errno));
return -1;
}
return 0;
}else{
fd = open(filename, O_RDONLY);
if(fd == -1)
{
DEBUG_INFO("[ERROR]:fail to open: %s\n",strerror(errno));
return -1;
}
filesize = lseek(fd, 0, SEEK_END);
close(fd);
head.file_is_exist = EXIST;
head.filesize = filesize;
strcpy(head.filename, filename);
ret = tcp_send_pack(sockfd, &head, sizeof(head));
if(ret != sizeof(file_protocol_t))
{
DEBUG_INFO("[ERROR]:fail to tcp_send_pack: %s\n",strerror(errno));
return -1;
}
}
return filesize;
}
int client_upload_file(const char *filename, int sockfd)
{
int filesize;
int fd;
ssize_t rbytes = 0, sbytes = 0;
int upload_size = 0;
char buffer[1024] = {0};
//1、将协议头发送给服务器
filesize = send_protocol_head(filename, sockfd, UPLOAD);
if(filesize == -1)
{
return -1;
}
//2、循环读取文件数据并发送给服务器
fd = open(filename, O_RDONLY);
if(fd == -1)
{
DEBUG_INFO("[ERROR]:fail to open: %s\n",strerror(errno));
return -1;
}
while(1)
{
bzero(buffer, sizeof(buffer));
rbytes = read(fd, buffer, sizeof(buffer));
if(rbytes == -1)
{
DEBUG_INFO("[ERROR]:fail to read: %s\n",strerror(errno));
return -1;
}else if(rbytes == 0)
{
//表示读到文件尾了
break;
}
sbytes = tcp_send_pack(sockfd, buffer, rbytes);
if(sbytes != rbytes)
{
DEBUG_INFO("[ERROR]:fail to tcp_send_pack: %s\n",strerror(errno));
return -1;
}
upload_size += sbytes;
}
close(fd);
return upload_size;
}
int recv_reply_server(int sfd, file_protocol_t *p_head)
{
return recv_protocol_head(sfd, p_head);
}
int client_down_file(const char *filename, int sockfd)
{
int recv_size = 0;
int filesize = 0;
int ret;
file_protocol_t head;
bzero(&head, sizeof(file_protocol_t));
//1、将协议头发送给服务器
ret = send_protocol_head(filename, sockfd, DOWNLOAD);
if(ret == -1)
{
return -1;
}
ret = recv_protocol_head(sockfd, &head);
if(ret == -1)
{
return -1;
}
if(head.file_is_exist != EXIST)
{
DEBUG_INFO("[ERROR]:file is no exist.");
return -1;
}
recv_size = recv_filedata(sockfd, filename, head.filesize);
return recv_size;
}
server.c
#include "tcp_socket.h"
#include "file_transfer.h"
#include "debug.h"
#include
#include
#include
#include
void *do_task(void *arg)
{
int cfd = *(int *)arg;
recv_client_file_transfer(cfd);
close(cfd);
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
int sfd, cfd;
int ret;
pthread_t tid;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(struct sockaddr_in);
if(argc!=3)
{
fprintf(stderr, "Usage: %s ip port", argv[0]);
exit(EXIT_FAILURE);
}
sfd = create_tcp_server_socket(argv[1],atoi(argv[2]));
if(sfd == -1)
{
exit(EXIT_FAILURE);
}
while(1)
{
bzero(&client_addr, addr_len);
cfd = wait_for_connect(sfd, &client_addr);
if(cfd == -1)
{
exit(EXIT_FAILURE);
}
show_tcp_network_addr(&client_addr);
ret = pthread_create(&tid, NULL, do_task, (void *)&cfd);
if(ret != 0)
{
DEBUG_INFO("[ERROR]:%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
pthread_detach(tid);
}
close(sfd);
return 0;
}
client.c
#include "tcp_socket.h"
#include "file_transfer.h"
#include "debug.h"
#include
int main(int argc, char const *argv[])
{
int sfd, cfd;
int upload_size = 0;
if(argc!=4)
{
fprintf(stderr, "Usage: %s ", argv[0]);
exit(EXIT_FAILURE);
}
sfd = create_tcp_client_socket(argv[1], atoi(argv[2]));
upload_size = client_down_file(argv[3], sfd);
if(upload_size == -1)
{
DEBUG_INFO("[ERROR]:fail to open: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
return 0;
}
【图片】