C语言实现Linux Socket文件传输实例
本文展示如何使用C语言在Linux系统中基于TCP协议实现可靠的Socket文件传输功能。内容涵盖服务器端监听与发送逻辑,以及客户端连接、接收与保存逻辑,包含完整的错误处理机制。
原理与核心流程
基于TCP的文件传输依赖于稳定的双向字节流。其核心交互顺序为:Server负责绑定端口并等待客户端接入,获取连接后执行握手消息交换(可选)并打开本地文件进行读取;Client通过IP和端口发起连接,验证服务端响应后创建输出文件,进入循环从Socket缓冲区接收数据块并写入磁盘。
准备条件
- 操作系统:Linux (内核版本不限,标准POSIX接口)。
- 依赖库:需链接
libsocket及librt(视系统而定),通常编译命令为gcc -o server server.c。 - 文件权限:确保服务器对源文件有读权限,客户端对目标路径有写权限。
第1步:配置并运行服务器端 (server.c)
目的:启动后台服务,侦听指定端口并对外发送名为“data1”的文本文件。
关键参数:
HELLO_WORLD_SERVER_PORT: 7754 (通信端口号)。BUFFER_SIZE: 1024 (每次I/O操作的缓冲区大小)。
服务端实现了标准的阻塞式TCP监听模型。首先初始化 sockaddr_in 结构体并将端口绑定至任意可用网卡接口 (INADDR_ANY)。调用 listen() 后进入无限循环调用 accept() 获取新连接。一旦连接建立,先发送一条欢迎信息,随后以二进制安全的方式读取本地文件 data1,按 BUFFER_SIZE 分片调用 send() 传输,直到文件末尾。
////////////////////////////////////
//服务器代码
///////////////////////////////////
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
#include <time.h> //for time_t and time
#define HELLO_WORLD_SERVER_PORT 7754
#define LENGTH_OF_LISTEN_QUEUE 20
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
//设置一个socket地址结构server_addr,代表服务器internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr)); //把一段内存区的内容全部设置为0
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htons(INADDR_ANY);
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
FILE *stream;
//创建用于internet的流协议(TCP)socket,用server_socket代表服务器socket
int server_socket = socket(AF_INET,SOCK_STREAM,0);
if( server_socket < 0)
{
printf("Create Socket Failed!");
exit(1);
}
//把socket和socket地址结构联系起来
if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))
{
printf("Server Bind Port : %d Failed!
"HELLO_WORLD_SERVER_PORT);
exit(1);
}
//server_socket用于监听
if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )
{
printf("Server Listen Failed!");
exit(1);
}
while (1) //服务器端要一直运行
{
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);
if ( new_server_socket < 0)
{
printf("Server Accept Failed!\n");
break;
}
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strcpy(buffer,"Hello,World! 从服务器来!");
strcat(buffer,"\n"); //C语言字符串连接
send(new_server_socket,buffer,BUFFER_SIZE,0);
bzero(buffer,BUFFER_SIZE);
//接收客户端发送来的信息到buffer中
length = recv(new_server_socket,buffer,BUFFER_SIZE,0);
if (length < 0)
{
printf("Server Recieve Data Failed!\n");
exit(1);
}
printf("\n%s",buffer);
if((stream = fopen("data1","r"))==NULL)
{
printf("The file 'data1' was not opened! \n");
exit(1);
}
else
printf("The file 'filename' was opened! \n");
bzero(buffer,BUFFER_SIZE);
int lengsize = 0;
while((lengsize = fread(buffer,1,1024,stream)) > 0)
{
printf("lengsize = %d\n",lengsize);
if(send(new_server_socket,buffer,lengsize,0)<0)
{
printf("Send File is Failed\n");
break;
}
bzero(buffer, BUFFER_SIZE);
}
if(fclose(stream))
printf("The file 'data' was not closed! \n");
exit(1);
//关闭与客户端的连接
close(new_server_socket);
}
//关闭监听用的socket
close(server_socket);
return 0;
}
第2步:启动并测试客户端 (client.c)
目的:连接到已运行的服务端,接收文件流并保存为本地 data 文件。
运行方式:需要传入服务端IP作为参数,例如 .\client 127.0.0.1 (Windows CMD) 或 ./client 127.0.0.1 (Linux Terminal)。
客户端首先检查命令行参数数量。成功创建流式Socket后,将自动分配临时端口并绑定到本机任何IP上。通过 inet_aton(argv[1]) 解析传入的服务端IP并填入 server_addr 结构体。随后发起 connect() 请求。连接成功后,先接收来自服务端的握手字符串,清空缓冲区后向服务端回传确认信号,然后立即打开文件 data 进入 while 循环,利用 recv() 持续填充缓冲区,并使用 fwrite() 将其持久化写入磁盘。
////////////////////////////////////
//客户端代码
///////////////////////////////////
#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h> // for socket
#include <sys/socket.h> // for socket
#include <stdio.h> // for printf
#include <stdlib.h> // for exit
#include <string.h> // for bzero
#include <time.h> //for time_t and time
#include <arpa/inet.h>
#define HELLO_WORLD_SERVER_PORT 7754
#define BUFFER_SIZE 1024
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: ./%s ServerIPAddress\n",argv[0]);
exit(1);
}
//time_t now;
FILE *stream;
//设置一个socket地址结构client_addr,代表客户机internet地址, 端口
struct sockaddr_in client_addr;
bzero(&client_addr,sizeof(client_addr)); //把一段内存区的内容全部设置为0
client_addr.sin_family = AF_INET; //internet协议族
client_addr.sin_addr.s_addr = htons(INADDR_ANY); //INADDR_ANY表示自动获取本机地址
client_addr.sin_port = htons(0); //0表示让系统自动分配一个空闲端口
//创建用于internet的流协议(TCP)socket,用client_socket代表客户机socket
int client_socket = socket(AF_INET,SOCK_STREAM,0);
if( client_socket < 0)
{
printf("Create Socket Failed!\n");
exit(1);
}
//把客户机的socket和客户机的socket地址结构联系起来
if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))
{
printf("Client Bind Port Failed!\n");
exit(1);
}
//设置一个socket地址结构server_addr,代表服务器的internet地址, 端口
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自程序的参数
{
printf("Server IP Address Error!\n");
exit(1);
}
server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr);
//向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)
{
printf("Can Not Connect To %s!\n",argv[1]);
exit(1);
}
char buffer[BUFFER_SIZE];
bzero(buffer,BUFFER_SIZE);
//从服务器接收数据到buffer中
int length = recv(client_socket,buffer,BUFFER_SIZE,0);
if(length < 0)
{
printf("Recieve Data From Server %s Failed!\n", argv[1]);
exit(1);
}
printf("\n%s\n",buffer);
bzero(buffer,BUFFER_SIZE);
bzero(buffer,BUFFER_SIZE);
strcpy(buffer,"Hello, World! From Client\n");
//向服务器发送buffer中的数据
send(client_socket,buffer,BUFFER_SIZE,0);
if((stream = fopen("data","w+t"))==NULL)
{
printf("The file 'data' was not opened! \n");
}
else
bzero(buffer,BUFFER_SIZE);
length = 0;
while( length = recv(client_socket,buffer,BUFFER_SIZE,0))
{
if(length < 0)
{
printf("Recieve Data From Server %s Failed!\n", argv[1]);
break;
}
int write_length = fwrite(buffer,sizeof(char),length,stream);
if (write_length<length)
{
printf("File is Write Failed\n");
break;
}
bzero(buffer, BUFFER_SIZE);
}
printf("Recieve File From Server[%s] Finished\n", argv[1]);
//关闭 文件
fclose(stream);
//关闭socket
close(client_socket);
return 0;
}
第3步:结果判断与排错
完成状态:当服务端控制台打印完最后一次分片大小且退出程序,同时客户端输出 Recieve File From Server[...] Finished 时,当前目录下应生成名为 data 的新文件。比对文件大小与服务端 data1 一致即为成功。
常见问题排查:
- 端口冲突:若服务端报错
Bind Port Failed,说明7754端口已被占用,可通过netstat -anp | grep 7754查看进程并更换代码中的宏定义值。 - 连接被拒:客户端报错
Connect Fail通常意味着服务端未启动、防火墙拦截了7754端口,或输入的IP地址不匹配(注意区分IPv4和IPv6)。 - 文件截断/乱码:由于使用了
recv()循环判断返回值,只要磁盘空间充足且中途无网络中断,文件内容通常能保持完整。
总结
通过上述步骤,您可以快速构建一个基础的点对点文件传输通道。该方案适合小文件和局域网环境下的轻量级数据传输。以上就是C语言实现Linux Socket文件传输的详细内容,更多关于C语言Socket开发的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









