//实现两台计算机进行文件传输,包括跨平台传输即linux与windows之间
//TCP的文件传输
//文件大小不限制,需要做到将大文件分包去做
server.c
//服务端程序
int main(int arg,char * args[ ])
{
if(arg < 2)
{
printf("scanf parameter failed\n");
return 0;
}
int port = itoi(args[1]);
if(port == 0)
{
printf("port %d is invalid\n ",port);
return 0;
}
printf("receive begin\n");
if(recv_work(port) == 1)
printf("receive success\n");
else
printf("receive failed\n");
return 0;
}
client.c
//实现两台计算机进行文件传输,包括跨平台传输即linux与windows之间
//TCP的文件传输
//文件大小不限制,需要做到将大文件分包去做
//编译时传入的参数是包括:服务器IP地址、端口号、传送的文件名
//client端
int main(int arg,char * args[ ])
{
//先是判断传入的参数个数
if(arg < 4)
{
printf("scanf parameter failed\n");
return 0;
}
//判断端口号
int port = atoi(args[2]);
if(port == 0)
{
printf("port %d is invalid\n ",port);
return 0;
}
printf("%s send begin\n",args[3]);
//将调用一个send_work函数传入服务器IP地址、端口号、传送的文件名
if(send_work(args[1],port,args[3]) == 1)
{
sleep(3);
printf("%s send success\n",args[3]);
}
else
{
printf("%s send failed\n",args[3]);
}
return EXIT_SUCCESS;
}
pub.h
#ifndef PUB_H_
#define PUB_H_
int send_work(const char * hostname,int port,const char * filename);
int recv_work(int port);
#endif /* PUB_H_ */
pub.c
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#define SOCKET int
#endif
#include <stdio.h>
#include "pub.h"
#define BUFSIZE 262144 //1024 * 256
//为什么要定义一个宏,解释一下,因为此程序可以保证在linux与windows系统下均可运行。
//#ifdef WIN
//#include <WinSock2.h>
//#else 为什么这样写呢,在windows下socket被封装在此头文件下,而且套接口的类型为SOCKET,而linux下的套接口为int型,故作此标记
int init_socket()
{
//如果是windows系统,执行如下代码,linux系统直接略过此代码
#ifdef WIN
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
return -1;
}
if (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
{
WSACleanup();
return -1;
}
#endif
return 0;
}
SOCKET socket_connect(const char * hostname,int port)//连接IP地址和port端口号
{
if(init_socket() == -1)//因为linux与windows系统下使用socket有区别,windows下必须使用此函数初始化(同样用到宏)
return 0;
SOCKET st = socket(AF_INET,SOCK_STREAM,0);
if(st == 0)
return 0;
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(hostname);
if(connect(st,(struct sockaddr *) &addr,sizeof(addr)) == -1)
{
printf("connect to %s:%d failed %s\n", hostname, port, strerror(errno));
return 0; // 连接失败,返回0
}
else
{
return st;
}
}
void getfilename(const char * filename, char * name)
{
int len = strlen(filename);
int i;
for(i = (len -1);i >= 0;i--)
{
if((filename[i] == '\\') ||(filename[i] == '/'))
{
break;
}
}
strcpy(name,&filename[i + 1]);
}
//连接到hostname指定的IP地址和port端口号
int send_work(const char * hostname,int port,const char * filename)
{
SOCKET st = socket_connect(hostname,port);
if(st == 0)
return 0;
//连接成功后,需要将传送的文件打开
FILE * fd = fopen(filename,"rb");
if(fd == NULL)//判断文件描述符,看文件是否打开
{
printf("open %s failed\n",filename);
return 0;
}
char *buf = malloc(BUFSIZE) ;//申请一个缓冲区,将文件数据放置在此
memset(buf,0,BUFSIZE);
//将完整的文件名解析出来
getfilename(filename,buf);
//将解析出来的文件名先发送给服务端,等待服务端接收,若接收成功并返回一个信号给客户端
int rc = send(st,buf,strlen(buf),0);
if(rc <= 0)//在判断一下是否成功发出
{
if(rc < 0)
printf("send failed %s\n", strerror(errno));
else
printf("socket disconnect\n");
}
else
{
memset(buf,0,sizeof(buf));
//等待服务器端传来的消息
if(recv(st,buf,BUFSIZE,0) <= 0)
{
printf("socket disconnect\n");
}
else
{
if(strncmp(buf,"OK",2) == 0)
{
while(1)
{
memset(buf,0,BUFSIZE);
rc = fread(buf,1,BUFSIZE,fd);
if(rc <= 0)
{
if (rc < 0)
printf("fread failed %s\n", strerror(errno));
break;
}
else
{
rc = send(st,buf,rc,0);
if(rc <= 0)
{
if (rc < 0)
printf("fread failed %s\n", strerror(errno));
else
printf("socket disconnect\n");
break;
}
printf("我已发送\n");
}
}
}
}
}
fclose(fd);
free(buf);
#ifdef WIN
closesocket(st);
WSACleanup();
#else
close(st);
#endif
return 1;
}
SOCKET socket_create(int port)
{
SOCKET st = socket(AF_INET,SOCK_STREAM,0);//初始化socket
if(st == 0)
return 0;
#ifdef WIN
const char on = 0;
#else
int on = 0;
#endif
if (setsockopt(st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
{
printf("setsockopt failed %s\n", strerror(errno));
return EXIT_FAILURE;
}
struct sockaddr_in addr;//定义一个IP地址的结构
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8080);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//服务器端程序,需要使用bind将IP与server程序绑定
if(bind(st,(struct sockaddr *) &addr,sizeof(addr)) == -1)
{
printf("bind failed %s\n", strerror(errno));
return 0;
}
if(listen(st,20) == -1)
{
printf("listen failed %s\n", strerror(errno));
return 0;
}
printf("listen success\n");
return st;
}
// server端socket开始accept的函数
SOCKET socket_accept(SOCKET client_st)
{
struct sockaddr_in client_addr;
memset(&client_addr,0,sizeof(client_addr));
#ifdef WIN
int len = 0;
#else
unsigned int len = 1;
#endif
len = sizeof(client_addr);
SOCKET listen_st = accept(client_st,(struct sockaddr *) &client_addr,&len);//阻塞调用
if (listen_st == -1)
{
printf("accept failed %s\n", strerror(errno));
return EXIT_FAILURE;
}
else
{
printf("accept by %s\n",inet_ntoa(client_addr.sin_addr));
return listen_st;
}
}
// server端socket在port指定的断口上listen,接收来自client发送的文件
int recv_work(int port)
{
SOCKET st = socket_create(port);// 建立server端socket,在port指定的端口listen
if(st == 0)
return 0;
// 如果有client连接到,socket_accept函数返回client的socket
SOCKET listen_st = socket_accept(st);
if(listen_st == 0)
return 0;
char *buf = malloc(BUFSIZE);
memset(buf,0,BUFSIZE);
FILE * fd = NULL;
size_t rc = recv(listen_st,buf,BUFSIZE,0);//接收来自client的数据,客户端第一次要发送的文件名称
if(rc <= 0)
{
if(rc < 0)
printf("receive failed %s\n", strerror(errno));
else
printf("socket disconnect\n");
}
else
{
printf("receicing %s\n",buf);
fd = fopen(buf,"wb");//以只写的方式打开
if(fd == NULL)
{
printf("open %s failed %s\n", buf, strerror(errno));
return 0;
}
else
{
memset(buf,0,BUFSIZE);
strcpy(buf,"OK");
rc = send(listen_st,buf,strlen(buf),0);
if(rc <= 0)
{
if(rc < 0)
printf("send failed %s\n", strerror(errno));
else
printf("socket disconnect\n");
}
while(1)
{
memset(buf,0,BUFSIZE);
rc = recv(listen_st,buf, BUFSIZE, 0);
if(rc <= 0)// 如果client连接断开,代表文件传递完成,或者网络意外中断,循环break
{
if(rc < 0)
printf("receive failed %s\n", strerror(errno));
else
printf("socket disconnect\n");
break;
}
else
{
fwrite(buf,1,rc,fd);// 将从client端收到的内容写入文件
}
}
}
}
if(fd)
fclose(fd);
free(buf);
#ifdef WIN
closesocket(st);
closesocket(listen_st);
WSACleanup();
#else
close(st);
close(listen_st);
#endif
return 1;
}
在windows下的makfile代码:
.SUFFIXES:.c .o
CC=gcc
SERVERSRCS=file_server.c\
pub.c
CLIENTSRCS=file_socket.c\
pub.c
SERVEROBJS=$(SERVERSRCS:.c=.o)
CLIENTOBJS=$(CLIENTSRCS:.c=.o)
SERVEREXEC=server.exe
CLIENTEXEC=client.exe
all: $(SERVEROBJS) $(CLIENTOBJS)
$(CC) -static -o $(SERVEREXEC) $(SERVEROBJS)
$(CC) -static -o $(CLIENTEXEC) $(CLIENTOBJS)
@echo '----------------ok----------------'
.c.o:
$(CC) -Wall -DWIN -g -o $@ -c $<
clean:
rm -f $(SERVEROBJS)
rm -f $(CLIENTOBJS)
rm -f core*
linux下的makefile文件:
.SUFFIXES:.c .o
CC=gcc
SERVERSRCS=file_server.c\
pub.c
CLIENTSRCS=file_socket.c\
pub.c
SERVEROBJS=$(SERVERSRCS:.c=.o)
CLIENTOBJS=$(CLIENTSRCS:.c=.o)
SERVEREXEC=server
CLIENTEXEC=client
all: $(SERVEROBJS) $(CLIENTOBJS)
$(CC) -o $(SERVEREXEC) $(SERVEROBJS)
$(CC) -o $(CLIENTEXEC) $(CLIENTOBJS)
@echo '----------------ok----------------'
.c.o:
$(CC) -Wall -g -o $@ -c $<
clean:
rm -f $(SERVEROBJS)
rm -f $(CLIENTOBJS)
rm -f core*