目录
1.上传文件思路
2.下载文件思路
3.上传文件代码
4.下载文件代码
5.运行格式
1.上传文件思路
上传文件就相当于客户端发送文件
步骤:
- 创建套接字
- 连接服务器
- 获取文件大小
- 循环少量多次发送
- 关闭文件和套接字
2.下载文件思路
下载文件就相当于服务器端接收文件
步骤:
- 创建套接字
- 绑定服务器信息
- 监听
- 接收数据
- 关闭文件描述符
3.上传文件代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define MSG_LEN 4096
// 相当于客户端上传文件
// a.out 服务器端IP 服务器端口 要上传文件路径
int main(int argc, char *argv[])
{
if (argc != 4)
{
printf("参数有误!\n");
return -1;
}
// 先检查文件存不存在
if (access(argv[3], F_OK) == -1)
{
printf("文件不存在\n");
return -1;
}
// 创建套接字
int send_fd = socket(AF_INET, SOCK_STREAM, 0);
if (send_fd == -1)
{
perror("socker error...");
return -1;
}
struct sockaddr_in send_inf;
send_inf.sin_family = AF_INET;
send_inf.sin_addr.s_addr = inet_addr(argv[1]);
send_inf.sin_port = htons(atoi(argv[2]));
// 连接
if (connect(send_fd, (struct sockaddr *)&send_inf, sizeof(send_inf)) == -1)
{
perror("connnect error...");
return -1;
}
else
{
// 发送数据
// 先获取文件大小
struct stat sb;
memset(&sb, 0, sizeof(sb));
stat(argv[3], &sb);
long file_size = sb.st_size;
printf("文件大小是:%ld\n", file_size);
int file_fd = open(argv[3], O_RDONLY);
if (file_fd == -1)
{
perror("open error...");
return -1;
}
char msg[MSG_LEN] = "\0";
int i;
// 循环发送数据
for (i = 0; i < (file_size / MSG_LEN); i++)
{
memset(msg, 0, sizeof(char) * MSG_LEN);
// 先读
int read_ret = read(file_fd, msg, MSG_LEN);
if (read_ret == -1)
{
perror("read error...");
printf("%d\n", __LINE__);
return -1;
}
// 再写
int write_ret = write(send_fd, msg, read_ret);
if (write_ret == -1)
{
perror("write error...");
return -1;
}
usleep(2000);
}
if (file_size % MSG_LEN != 0)
{
// 最后一次
memset(msg, 0, sizeof(char) * MSG_LEN);
int read_ret = read(file_fd, msg, MSG_LEN); // 因为read是安全的,所以可以直接读MSG_LEN,即使数据不够也不会多读
if (read_ret == -1)
{
perror("read error...");
return -1;
}
// 再写
int write_ret = write(send_fd, msg, read_ret);
if (write_ret == -1)
{
perror("write error...");
return -1;
}
}
printf("发送成功!\n");
// 关闭文件描述符
close(send_fd);
close(file_fd);
}
return 0;
}
4.下载文件代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#define MSG_LEN 4096
// 相当于服务器接收文件
// a.out 服务器端口 存放文件路径
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("参数有误!\n");
return -1;
}
// 创建套接字
int rec_fd = socket(AF_INET, SOCK_STREAM, 0);
if (rec_fd == -1)
{
perror("socker error...");
return -1;
}
struct sockaddr_in rec_inf;
rec_inf.sin_family = AF_INET;
rec_inf.sin_addr.s_addr = htonl(INADDR_ANY);
rec_inf.sin_port = htons(atoi(argv[1]));
// 绑定
if (bind(rec_fd, (struct sockaddr *)&rec_inf, sizeof(rec_inf)) == -1)
{
perror("bind error...");
return -1;
}
// 监听
if (listen(rec_fd, 20) == -1)
{
perror("listen error...");
return -1;
}
int send_fd = accept(rec_fd, NULL, NULL);
if (send_fd == -1)
{
perror("accpet error...");
return -1;
}
else
{
// 接收数据
char msg[MSG_LEN] = "\0";
umask(0000);
int file_fd = open(argv[2], O_CREAT | O_WRONLY, 0777);
if (file_fd == -1)
{
perror("open error...");
return -1;
}
while (1)
{
memset(msg, 0, sizeof(char) * MSG_LEN);
int read_ret = read(send_fd, msg, MSG_LEN);
if (read_ret == -1)
{
perror("read error...");
return -1;
}
else if (read_ret == 0)
{
break;
}
else
{
if (write(file_fd, msg, strlen(msg)) == -1)
{
perror("write error...");
return -1;
}
}
}
close(file_fd);
close(rec_fd);
}
return 0;
}
5.运行格式
一、发送端(客户端)
a.out 服务器端IP 服务器端口 要上传文件路径
二、接收端(服务器端)
a.out 服务器端口 存放文件路径
(注意:同一台主机端口号不能相同)