下面是一个简单的TCP文件传输的例子,实现环境:Linux C
Server.c
// 向客户端发送文件
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define MAXBUFF 1024
// 通过sock来发送指定的文件
int sendFile(char *srcFile, int sock)
{
int inFile;
if((inFile = open(srcFile, O_RDONLY)) == -1) //只读方式打开test.txt ,iffile文件指针
{
printf("找不到文件[%s]或打不开, 停止运行\n", srcFile);
return -1; // 发送文件失败
}
int nread;
char buf[MAXBUFF] = {0};
while((nread = read(inFile, buf, MAXBUFF)) > 0)
{
if(write(sock, buf, nread) == -1) // 将缓冲区的内容写到sock
printf("写sock出了错\n");
}
close(inFile);
return 0; // 发送文件成功
}
int main()
{
int sock,length,clilen;
struct sockaddr_in server, client;
/******************************建立Socket连接*********************************/
sock = socket(AF_INET,SOCK_STREAM,0); //申请socket资源
if (sock < 0)
{
perror("socket");
return 1;
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY; // 必然的,这里指的是Internet协议*/
server.sin_port = 0; // 这里,是让系统自动分配一个端口号,在1024到5000之间65535个端口 ,端口设为0,系统自动分配
if (bind(sock, (struct sockaddr *)&server, sizeof(server)) < 0) // 将IP地址和端口号绑到sock上
{
perror("bind");
return 1;
}
length = sizeof(server);
if (getsockname(sock, (struct sockaddr *)&server, &length) < 0) /*获得指定socket的本地地址,成功返回0,错误返回-1*/
{
perror("getsockname");
return 1;
}
printf("Socket port #%d\n", ntohs(server.sin_port)); /* 打印出系统分的端口号,给client用*/
listen(sock, 5); /*5个连接请求排队等待,一般5个 Pause Here 等待client连接*/
/****************现在是等待客户来连接,如果来客户了,那就建好了socket,就可以当文件使用**********/
clilen = sizeof(client);
int msgsock = accept(sock,(struct sockaddr *)&client,(int *) &clilen); /*创建一个新的与sock相同的socket并返回其值*/
if (msgsock == -1)
perror("accept");
else
{
char srcFile[] = "test.txt";
if(sendFile(srcFile, msgsock) == 0)
printf("发送文件[%s]成功\n", srcFile);
else
printf("发送文件[%s]失败\n", srcFile);
}
close(msgsock); // 关闭临时套接字
close(sock);
return 0;
}
Client.c
// 功能:接收服务器发送过来的数据,保存到本地文件
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define MAXBUFF 1024
#define PERM 0644 // 创建文件的默认属性
// 通过sock接收数据保存到文件destFile
int recvFile(char *destFile, int sock)
{
int outFile, nread;
char buf[MAXBUFF] = {0};
if((outFile = open(destFile, O_WRONLY|O_CREAT|O_TRUNC, PERM)) == -1) //创建文件
return 1;
while((nread = read(sock, buf, MAXBUFF)) > 0) /*从sock读取传来的文件内容到缓冲区*/
{
if(write(outFile, buf, nread) == -1) /*将缓冲区的内容写到文件里*/
{
printf("写文件时出错, 中止接收文件\n");
close(outFile);
return 1;
}
}
close(outFile);
return 0;
}
int main(int argc, char *argv[])
{
int sock;
struct sockaddr_in server;
struct hostent *hp;
if(argc < 3)
{
printf("Usage: %s <hostname> <server port>\n", argv[0]);
return 1;
}
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
perror("socket");
return 1;
}
server.sin_family = AF_INET;
hp = gethostbyname(argv[1]); /*根据主机名查地址,返回指针指向hostent结构*/
if (hp == 0)
{
fprintf(stderr, "%s: unknown host\n", argv[1]);
return 1;
}
memcpy((char *)&server.sin_addr,(char *)hp->h_addr, hp->h_length); // 拷贝Internet地址
server.sin_port = htons(atoi(argv[2])); // argv[2]是服务器端口号
if (connect(sock,(struct sockaddr *)&server,sizeof(server)) < 0) // 根据server地址连接sock,建立一条真实的连接
{
perror("connect");
close(sock);
return 1;
}
char destFile[] = "test_out.txt";
if(recvFile(destFile, sock) == 0)
{
printf("接收文件[%s]成功\n\n", destFile);
}
else
{
printf("创建输出文件[%s]出错, 请检查\n", destFile);
}
close(sock);
return 0;
}
如果要检查文件传输过程有没有出错,可以通过命令:wc或计算MD5值来作比较。
我的检测结果:
[zcm@t #64]$cat test.txt |wc
89 183 2901
[zcm@t #65]$cat test_out.txt |wc
89 183 2901
[zcm@t #66]$md5sum test.txt test_out.txt
fffb6bcab6154aad9f7dfe4f5d945bc3 test.txt
fffb6bcab6154aad9f7dfe4f5d945bc3 test_out.txt