我是靠谱客的博主 诚心山水,最近开发中收集的这篇文章主要介绍C语言:实现Linux系统下利用TCP协议传输文件到阿里云服务器1. 实现一次传输2. 程序流程3. 文件传输源代码,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
最近学习了Linux下的TCP
网络编程,想实践一下,于是写了利用TCP
协议、传输文件到阿里云服务器的客户端程序和服务端程序。
首先来看看实现的效果。
1. 实现一次传输
虚拟机Ubuntu
的/桌面/TCP_File
目录下,有如下文件:
将其发送到自己的阿里云服务器的/home/www/website/
目录下。
首先在云服务器端运行server
:
Ubuntu系统运行client
,并输入相应的参数(云服务器地址、文件目录/文件名):
按下回车后,各界面上的响应:
-
客户端:
-
服务端
查看服务器端,文件已传输完成:
2. 程序流程
-
客户端
-
服务端
3. 文件传输源代码
1. 客户端client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
// 端口号6666
#define PORT 6666
// 定义buffer大小
#define BUF_SIZE 1024
// #define LISTEN_LENGTH 20
int main(int argc, char *argv[])
{
printf("客户端启动...n");
// 简单判断用户输入的命令行参数,若不符合规范则给出提示
if (argc != 3)
{
// argv[0]是输入的第一个参数
printf("请输入正确的参数!n");
printf("格式: %s 服务器主机地址 目录/文件名 n", argv[0]);
printf("举例: %s 47.110.144.145 XXX.txt n", argv[0]);
// exit(1)表示异常退出
exit(1);
}
int sockfd, fp;
// int fp;
int recvBytes, sendBytes, readBytes;
// 定义buffer
unsigned char buffer[BUF_SIZE];
// 定义sockaddr_in结构体
struct sockaddr_in serv_addr;
struct hostent *host;
// 打开要发送的文件
// argv[2]是输入的第三个参数
// 打开文件方式为O_RDONLY只读方式
if ((fp = open(argv[2], O_RDONLY)) == -1)
{
printf("打开%s文件失败!n", argv[2]);
exit(1);
}
printf("打开%s文件成功!n", argv[2]);
// 解析hostname
// argv[1]是输入的第二个参数
if ((host = gethostbyname(argv[1])) == NULL)
{
printf("hostname错误!n");
exit(1);
}
// 创建socket流式套接字
// AF_INET允许与远程主机通信
// SOCK_STREAM代表流式套接字,采用TCP协议
// 失败返回-1
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("创建socket失败!n");
exit(1);
}
printf("创建socket成功!n");
// 请求连接服务器
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
// 将sin_zero清零
bzero(&(serv_addr.sin_zero), 8);
// 调用connect(),失败返回-1
if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
{
printf("连接服务器失败!n");
exit(1);
}
printf("连接服务器成功!n");
// ------------------通信阶段------------------
// 1.发送文件名
// 将buffer清零
memset(buffer, 0, sizeof(buffer));
// argv[2]是输入的第三个参数,文件名
strcpy(buffer, argv[2]);
// 调用send()
send(sockfd, buffer, strlen(buffer) + 1, 0);
printf("发送文件名完成!n");
// 将buffer清零
memset(buffer, 0, sizeof(buffer));
// 调用recv()
recvBytes = recv(sockfd, buffer, sizeof(buffer), 0);
// 2.发送数据
// 将buffer清零
memset(buffer, 0, sizeof(buffer));
printf("开始发送数据...n");
// 读文件,读取的字节数为buffer的长度
// 成功返回当前读取的字节数
// 如果返回值大于0,说明可能还没读取完毕,则继续执行一次
while ((readBytes = read(fp, buffer, BUF_SIZE)) > 0)
{
// 调用send(),将这次读取的数据发送
// readBytes 为这次读取的字节数
sendBytes = send(sockfd, buffer, readBytes, 0);
// 如果出错,返回-1,给出提示并退出
if (sendBytes < 0)
{
printf("× 发送文件失败!n");
exit(1);
}
// 将buffer清零
memset(buffer, 0, sizeof(buffer));
}
printf("√ 发送文件成功!n");
// 关闭文件
close(fp);
// 关闭套接字
close(sockfd);
printf("客户端退出...n");
}
2. 服务端server.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
// 端口号6666
#define PORT 6666
// 定义buffer大小
#define BUF_SIZE 1024
#define Name 100
// 定义listen中请求队列的大小
#define LISTEN_LENGTH 20
void main()
{
// 定义sockaddr_in结构体
struct sockaddr_in server_sockaddr, client_sockaddr;
int size, recvBytes, writeBytes, fp;
int sockfd, listenfd;
int i = 0;
unsigned char filePath[Name], filePath1[Name], filePath2[Name];
// unsigned char filePath1[Name], filePath2[Name];
// 定义buffer
unsigned char buffer[BUF_SIZE];
printf("服务端启动...n");
// 创建socket流式套接字,失败返回-1
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("socket创建失败!n");
exit(1);
}
printf("socket创建成功!listenfd=%dn", listenfd);
// 绑定地址及端口
server_sockaddr.sin_family = AF_INET;
server_sockaddr.sin_port = htons(PORT);
server_sockaddr.sin_addr.s_addr = INADDR_ANY;
// 将sin_zero清零
bzero(&(server_sockaddr.sin_zero), 8);
// 调用bind(),失败返回-1
if ((bind(listenfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr))) == -1)
{
printf("绑定失败!n");
exit(1);
}
printf("绑定成功!n");
// 监听客户端请求
// 调用listen(),失败返回-1
if (listen(listenfd, LISTEN_LENGTH) == -1)
{
printf("监听失败!n");
exit(1);
}
printf("监听连接请求...n");
// 接收连接
size = sizeof(client_sockaddr);
// 调用accept(),接收请求
sockfd = accept(listenfd, (struct sockaddr *)&client_sockaddr, &size);
if (sockfd == -1)
{
printf("连接失败!n");
exit(1);
}
printf("连接成功!n");
// ------------------通信阶段------------------
// 1.传输文件名
// 将buffer清零
bzero(buffer, BUF_SIZE);
// 调用recv(),接受数据保存在buffer
recvBytes = recv(sockfd, buffer, BUF_SIZE, 0);
// 把buffer中的数据复制到filePath
strcpy(filePath, buffer);
// 将buffer清零
memset(buffer, 0, sizeof(buffer));
// 将反馈信息放入buffer
strcpy(buffer, "文件名接收成功!n");
// 应答
send(sockfd, buffer, strlen(buffer) + 1, 0);
// 2.编辑文件名编辑,去除带'/'的路径
// 判断是否输入了目录
if (strchr(filePath, '/') != NULL)
{
// 输入了目录,作处理,去掉'/'
strcpy(filePath1, strrchr(filePath, '/'));
for (i = 1; filePath1[i] != '