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

使用条件编译可以分别在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 10240void 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 WINWSADATA wsaData;int Ret;// Initialize Winsock version 2.2if ((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 #endifreturn 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); //建立socketif (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/IPclient_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);//接收服务器的反馈 即OKif (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 WINclosesocket(st);if (WSACleanup() == SOCKET_ERROR){printf("WSACleanup failed with error %d\n", WSAGetLastError());return ERRORCODE;}#elseclose(st);#endifif (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); //初始化socketif (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/IPsockaddr.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 WINint len = 0;#elsesocklen_t len = 0; #endiflen = 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 WINclosesocket(listen_socket);closesocket(client_socket);if (WSACleanup() == SOCKET_ERROR){printf("WSACleanup failed with error %d\n", WSAGetLastError());return ERRORCODE;}#elseclose(listen_socket);close(client_socket);#endifif (fp){fclose(fp);}return 0;}

linux 下的Makefile文件

当你能爱的时候就不要放弃爱

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

相关文章:

你感兴趣的文章:

标签云: