linux/Windows 基于TCP协议的文件传输源码(有注释)

本文介绍了一个基于TCP协议的跨平台文件传输系统,该系统能在Windows和Linux环境下运行。通过条件编译实现不同操作系统的兼容性,并详细展示了客户端和服务端的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用条件编译可以分别在windows上和linux编译成功,基于TCP协议,使用socket通信技术。由于以二进制形式进行文件的读写,所有可以实现任意文件的传输。实现客户端发送,服务端接受文件。

测试环境windows7  vs2010,Ubutun14.04 gcc 

在windows 使用vs2010 编译时::在pub.c 文件开头加#define WIN

在linux 使用gcc 使用Makefile  编译时::在pub.c 文件开头删除#define WIN
服务端源码:server.c

#include<stdio.h>
#include<stdlib.h>
#include"pub.h"

int main(int argc, char *argv[])
{
	int i_port = 0;
	if (argc <= 1)
	{
		printf("Usage:port \n");
		return -1;
	}

	i_port = atoi(argv[1]); //
	if (i_port == 0)
	{
		printf("port error!");
		return -1;
	}

	if (recv_work(i_port) ==0)
	{
		printf("recv success! \n");
	} else
	{
		printf("recv failure! \n");
	}

	return 0;
}
客户端:client.c

#include<stdio.h>
#include<stdlib.h>
#include"pub.h"

int main(int argc, char *argv[])
{
	int i_port = 0;
	if (argc < 4)
	{
		printf("Usage:ip port filename,example:127.0.0.1 8080  a.txt \n");
		return -1;
	}
	i_port = atoi(argv[2]); //
	if (i_port == 0)
	{
		printf("port error!");
		return -1;
	}

	if (send_work(argv[1], i_port, argv[3]) == 0)
	{
		printf("send success! \n");
	} else
	{
		printf("send failure! \n");
	}
	return 0;
}

公共部分:pub.h

#ifndef PUB_H_
#define PUB_H_
//客户端发送函数入口
int send_work(const char *ip_str, int i_port, const char *filename);
//服务端发接收函数入口
int recv_work(int i_port);


#endif /* PUB_H_ */

函数体实现部分:pub.c  (要是在Windows上编译 在文件开头加#define WIN)

// 在windows上编译加#define WIN 
#ifdef WIN
#include <winsock2.h>
#pragma comment( lib, "ws2_32.lib" )
#else
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<errno.h>
#include<string.h>
#include <fcntl.h>
#define SOCKET int
#define INVALID_SOCKET -1
#endif
#define ERRORCODE -1

#include<stdio.h>
#define BUFFSIZE 10240


void get_filename(char *name, char *filename)
{
	int len;
	char *tmp = NULL;
	if (name == NULL)
		return;
	len = strlen(name);
	tmp = name + len - 1; //指向字符串末端
	while (tmp != name && *tmp != '\\' && *tmp != '/')
	{
		tmp--;
	} // 可能给的路径下的文件
	if(tmp == name) 
	{
		strcpy(filename, name);
	}
	else
	{
		strcpy(filename, tmp + 1);
	}

}
int init_socket()
{
#ifdef WIN

   WSADATA wsaData;
    
    int Ret;

   // Initialize Winsock version 2.2

	if ((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
	{
		printf("WSAStartup failed with error %d\n", Ret);
		if (WSACleanup() == SOCKET_ERROR)
		{
			printf("WSACleanup failed with error %d\n", WSAGetLastError());
		}
		return ERRORCODE;
	}
   // When your application is finished call WSACleanup
 
#endif
	return 0;
}
SOCKET socket_connect(char *ip_str, int i_port)
{
	SOCKET st;
	struct sockaddr_in client_sockaddr; //定义IP地址结构
	int i_connect_rv;
	if (init_socket() == -1)
	{
		printf("init socket fail! \n");
		return INVALID_SOCKET;
	}
	st = socket(AF_INET, SOCK_STREAM, 0); //建立socket
	if (st == INVALID_SOCKET)
	{
		printf("%s,%d:create socket error!",__FILE__,__LINE__);
		return INVALID_SOCKET;
	}

	memset(&client_sockaddr, 0, sizeof(client_sockaddr));
	client_sockaddr.sin_port = htons(i_port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)
	client_sockaddr.sin_family = AF_INET;	//设置结构类型为TCP/IP
	client_sockaddr.sin_addr.s_addr = inet_addr(ip_str);
	i_connect_rv = connect(st, (struct sockaddr*) &client_sockaddr,
			sizeof(client_sockaddr));
	if (i_connect_rv == -1)
	{
		printf("%s,%d:connect error!",__FILE__,__LINE__);
		return  INVALID_SOCKET;
	}
	return st;
}
int send_work(char *ip_str, int i_port, char *filename)
{
	int rv =0;
	FILE *fp = NULL ;
	char buf[BUFFSIZE];
	SOCKET st = socket_connect(ip_str, i_port);
	if (st == INVALID_SOCKET)
	{
		return ERRORCODE;
	}
	printf("connect success,start send file! \n");


	memset(buf, 0, BUFFSIZE);

	get_filename(filename, buf);

	fp = fopen(filename, "rb");//这里没有考虑文件名相同的情况
	if(fp ==NULL) 
	{
		printf("%s,%d:open file error! \n",__FILE__,__LINE__);
		return ERRORCODE;
	}

	printf("send file: %s..... \n", buf); //打印出文件名
	/* 将文件名发给服务器,然后等待服务器反馈后在发送文件内容,
	否则客户端发送的文件名和文件内容混在一起,无法区分 */
	rv = send(st, buf, strlen(buf), 0);

	if (rv <= 0)
	{
		printf("%s,%d:send error! \n",__FILE__,__LINE__);
		return ERRORCODE;
	}

	memset(buf, 0, BUFFSIZE);
	rv = recv(st, buf, BUFFSIZE, 0);//接收服务器的反馈 即OK
	if (rv <= 0)
	{
		printf("%s,%d:recv error! \n",__FILE__,__LINE__);
		return ERRORCODE;
	}
	//收到来自服务端的ok 后开始发送文件内容
	if (strncmp(buf, "OK", 2) == 0)	
	{
		while (1)
		{
			memset(buf, 0, BUFFSIZE);
			rv = fread(buf, 1, BUFFSIZE, fp);
			if (rv <= 0)// 等于0说明文件读完了 
			{
				if (rv < 0)
				{
					printf("%s,%d:fread file error! \n",__FILE__,__LINE__);
					return ERRORCODE;
				}
				break; 
			}
			rv = send(st, buf, rv, 0);
			if (rv <= 0)
			{
				printf("%s,%d:send error! \n",__FILE__,__LINE__);
				return ERRORCODE;
			}
		}
	}
// 释放资源 
#ifdef WIN
	closesocket(st);
	if (WSACleanup() == SOCKET_ERROR)
	{
		printf("WSACleanup failed with error %d\n", WSAGetLastError());
		return ERRORCODE;
	}
	
#else
	close(st);
#endif
	if (fp)
	{
		fclose(fp);
	}
	return 0;
}

SOCKET create_listensocket(int i_port)
{
	SOCKET listen_socket;
	struct sockaddr_in sockaddr; //定义IP地址结构
	//struct sockaddr_in clinet_sockaddr; //定义client IP地址结构
	if (init_socket() == -1)
	{
		printf("%s,%d:init socket error!",__FILE__,__LINE__);
		return INVALID_SOCKET;
	}

	listen_socket = socket(AF_INET, SOCK_STREAM, 0);  //初始化socket
	if (listen_socket == INVALID_SOCKET)
	{
		printf("%s,%d:socket create error!",__FILE__,__LINE__);
		return INVALID_SOCKET;
	}

	memset(&sockaddr, 0, sizeof(sockaddr));

	sockaddr.sin_port = htons(i_port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)
	sockaddr.sin_family = AF_INET;	//设置结构类型为TCP/IP
	sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);	//服务端是等待别人来连,不需要找谁的ip
	//这里写一个长量INADDR_ANY表示server上所有ip,这个一个server可能有多个ip地址,因为可能有多块网卡
	if (bind(listen_socket, (struct sockaddr *) &sockaddr, sizeof(sockaddr))
			== -1)
	{
		printf("%s,%d:recv error!",__FILE__,__LINE__);
		return INVALID_SOCKET; // 
	}
	if(listen(listen_socket,10)== -1) //bind 和listen出错
	{
		printf("%s,%d:listen error! \n",__FILE__,__LINE__);
		return INVALID_SOCKET;
	}
	return listen_socket;
}

SOCKET accept_socket(SOCKET listen_socket) // 获取连接来的客户端 
{
	struct sockaddr_in clinet_sockaddr;
	SOCKET client_socket;
	//windows 和linx 下accept函数最后一个参数有些区别
    //这里使用条件编译下
#ifdef WIN
	int len = 0;
#else
	socklen_t len = 0; 
#endif
	len = sizeof(struct sockaddr);
	memset(&clinet_sockaddr, 0, sizeof(clinet_sockaddr));
	client_socket = accept(listen_socket,
			(struct sockaddr*) &clinet_sockaddr, &len);
	if (client_socket == INVALID_SOCKET)
	{
		printf("%s,%d:accpet error! \n",__FILE__,__LINE__);
		return INVALID_SOCKET;
	}
	return client_socket;
}
int recv_work(int i_port) // 服务端接收文件 
{	
	char buf[BUFFSIZE];
	FILE *fp = NULL;
	int rv = 0;
	SOCKET client_socket ;
	SOCKET listen_socket = create_listensocket(i_port);

	if (listen_socket == INVALID_SOCKET)
	{
		return ERRORCODE;
	}
	printf("listen success port: %d \n",i_port);
	client_socket = accept_socket(listen_socket);
	if (client_socket == INVALID_SOCKET)
	{
		return ERRORCODE;
	}

	memset(buf, 0, BUFFSIZE);
	rv = recv(client_socket, buf, BUFFSIZE, 0);//获取文件名
	if (rv <= 0)
	{
		printf("%s,%d:recv error! \n",__FILE__,__LINE__);
		return ERRORCODE;
	}
	fp = fopen(buf, "wb");
	if(fp == NULL)
	{
		printf("%s,%d:fopen file error! \n",__FILE__,__LINE__);
		return ERRORCODE;
	}
	printf("accpet file: %s \n",buf);
	memset(buf, 0, BUFFSIZE);
	strcpy(buf, "OK");
	rv = send(client_socket, buf, strlen(buf), 0);//回复OK 表名文件名已经收到
	if (rv <= 0)
	{
		printf("%s,%d:send error! \n",__FILE__,__LINE__);
		return  ERRORCODE;
	}

	while (1) // 接收文件
	{
		memset(buf, 0, BUFFSIZE);
		rv = recv(client_socket, buf, BUFFSIZE, 0);//接收文件内容
		if (rv <= 0)
		{
			if (rv < 0)
			{
				printf("%s,%d:recv error!\n",__FILE__,__LINE__);
				return  ERRORCODE;
			}
			break;
		}
		rv = fwrite(buf, 1, rv, fp);//写入文件
		if (rv <= 0)
		{
			printf("%s,%d:file write error!",__FILE__,__LINE__);
			return ERRORCODE;
		}
	}
#ifdef WIN
	closesocket(listen_socket);
	closesocket(client_socket);
	if (WSACleanup() == SOCKET_ERROR)
	{
		printf("WSACleanup failed with error %d\n", WSAGetLastError());
		return ERRORCODE;
	}
	
#else
	close(listen_socket);
	close(client_socket);
#endif
	if (fp)
	{
		fclose(fp);
	}
	return 0;
}

linux 下的Makefile文件

.SUFFIXES:.c .o
CC = gcc
SRCS1=client.c\
    pub.c
SRCS2=server.c\
    pub.c	
OBJS1=$(SRCS1:.c=.o)
OBJS2=$(SRCS2:.c=.o)
EXEC1 = client
EXEC2 = server

start:$(OBJS1) $(OBJS2)
	$(CC) -g -o $(EXEC1) $(OBJS1) -lpthread
	$(CC) -g -o $(EXEC2) $(OBJS2) -lpthread
.c.o:
	$(CC) -g -o $@ -c $<
clean:
	rm -f $(OBJS1) $(OBJS2)
测试:在linux启动server


在widows 传输ss.mp4 文件


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值