需求分析
需要在两台 linux 虚拟机之间传送文件 程序功能:
(1)客户端:
a.可以向服务端发送一个本目录下指定的文件,文件名由用户输入; b.可以从服务端下载一个服务端目录下的文件,先从服务端获得文件名列表,再由用户输入需要的文件名。
(2)服务端:
a.可以监听来自客户端的连接请求; b.可以接收客户端传送的文件; c.可以向客户端传送一个指定的文件,文件由客户端给出。
(3)传送文件要求:任何二进制文件。
结果展示
1.客户端和服务器端的页面:
客户端:  服务器: 
2.客户端向服务端发送文件(一个指定文件或一个文件夹下的全部文件)
已知客户端本地文件夹里有: 
- 一个指定文件:
 查看服务端文件:成功  - 文件夹下全部文件(一次性提交)
 
3.客户端从服务端获得文件名列表
这里我偷懒了,直接在server.c里定义文件列表名  客户端查询即可: 
4.从服务端下载一个服务端目录下的文件
客户端:  服务端:  客户端download文件夹下: 
代码实现(部分)
服务器套接字的创建、绑定、监听
int init_Server(int port)
{
int serverSocket;
struct sockaddr_in server_addr;
// socket初始化
if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
return -1;
}
//服务端地址类型,地址及端口初始化
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(serverSocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
{
perror("connect");
return -1;
}
//设置服务器上的socket为监听状态
if (listen(serverSocket, 5) < 0)
{
perror("listen");
return -1;
}
return serverSocket;
}
服务器的接收与分析
serverSocket = init_Server(SERVER_PORT);
if (serverSocket < 0)
{
printf("服务器初始化失败!\n");
return 0;
}
printf("服务器初始化成功,监听端口:%d\n", SERVER_PORT);
//等待用户连接
while (1)
{
clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddr, (socklen_t *)&addr_len);
if (clientSocket < 0)
{
printf("服务端accept失败,程序退出。\n");
return 0;
}
printf("客户已连接:\n");
printf("IP is %s\n", inet_ntoa(clientAddr.sin_addr)); // inet_ntoa ip地址转换函数,将网络字节序IP转换为点分十进制IP
printf("Port is %d\n", htons(clientAddr.sin_port));
printf("等待消息...\n");
//解析客户端的需求类型
char recv_type[BUFFER_SIZE] = {0} ;
recv(clientSocket, recv_type, sizeof(recv_type), 0); //客户端的需求是1,2,3?
int tpye = atoi(recv_type);
printf("客户端的需求是: %d\n", tpye);
choose(tpye, clientSocket);
}
客户端的连接请求:
int connect_to_Server(char* serverIP, int port) {
struct sockaddr_in serverAddr;
int Socket;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port);
serverAddr.sin_addr.s_addr = inet_addr(serverIP);
if((Socket = socket(AF_INET, SOCK_STREAM, 0)) < 0){
printf("sock生成出错!\n");
return -1;
}
if(connect(Socket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) < 0) {
printf("connect失败!\n");
return -1;
}
return Socket;
}
全部代码会在之后更新,我会在评论区留下链接!!
|