windows与Linux实时传输数据,Linux利用socket实现两台pc之间的数据传输功能,包括windows到linux,TCP/IP实现...

Linux利用socket实现两台pc之间的数据传输功能,包括windows到linux

连接选项

-lWs2_32

代表要用Ws2_32.lib这个库

gcc编译选项,-D 代表定义一个宏,等同于在c语言当中定义 #defind WIN

在windows下,使用socket之前,必须使用WSAStartup初始化socket,程序运行结束以后必须调用WSACleanup释放相关资源

windown下,关闭socket使用closesocket函数

先看一下linux环境下的makefile文件

.SUFFIXES:.c .o

CC=gcc

SERVERSRCS=server.c\

pub.c

CLIENTSRCS=client.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*

下面是Windows环境下的makefile文件

.SUFFIXES:.c .o

CC=gcc

SERVERSRCS=server.c\

pub.c

CLIENTSRCS=client.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) -lWs2_32

$(CC) -static -o $(CLIENTEXEC) $(CLIENTOBJS) -lWs2_32

@echo '----------------ok----------------'

.c.o:

$(CC) -Wall -DWIN -o $@ -c $<

clean:

rm -f $(SERVEROBJS)

rm -f $(CLIENTOBJS)

rm -f core*

下面看client客户端的发送文件代码

#include

#include

#include "pub.h"

int main(int arg, char *args[])

{

if (arg < 4)// 如果参数小于3个,main函数退出

{

printf("usage:client host port filename\n");

return EXIT_FAILURE;

}

int iport = atoi(args[2]);// 将第二个参数转化为端口号

if (iport == 0)// 如果端口号为0,main函数退出

{

printf("port %d is invalid\n", iport);

return EXIT_FAILURE;

}

printf("%s send begin\n", args[3]);

if (send_work(args[1], iport, args[3]) == 1)// 第一个参数为IP地址,第二个参数为端口号,第三个参数为需要发送的文件名

printf("%s send success\n", args[3]);

else

printf("%s send fail\n", args[3]);

return EXIT_FAILURE;

}

然后是server接收端的接受代码

#include

#include

#include "pub.h"

int main(int arg, char *args[])

{

if (arg < 2)// 如果参数小于3个,main函数退出

{

printf("usage:server port\n");

return EXIT_FAILURE;

}

int iport = atoi(args[1]);// 将第二个参数转化为端口号

if (iport == 0)// 如果端口号为0,main函数退出

{

printf("port %d is invalid\n", iport);

return EXIT_FAILURE;

}

printf("recv is begin\n");

if (recv_work(iport) == 1)// 第一个参数为IP地址,第二个参数为端口号,第三个参数为需要发送的文件名

printf("recv success\n");

else

printf("recv fail\n");

return EXIT_FAILURE;

}

客户端和服务端用到的函数统统写在pub文件里面

#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_ */

#ifdef WIN

#include

#else

#include

#include

#include

#include

#include

#include

#define SOCKET int

#endif

#include

#include "pub.h"

#define BUFSIZE 262144 //1024 * 256

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]);

}

int init_socket()

{

// 如果是windows,执行如下代码

#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)

{

if (init_socket() == -1)

return 0;

SOCKET st = socket(AF_INET, SOCK_STREAM, 0); // 建立TCP socket

if (st == 0)

return 0;

struct sockaddr_in addr;

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

addr.sin_family = AF_INET;

addr.sin_port = htons(port);// 指定port为要连接的断口号

addr.sin_addr.s_addr = inet_addr(hostname);// 指定hostname为要连接的IP地址

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;// 连接成功返回socket描述符

}

}

// 连接到hostname指定的IP地址和port指定的端口号

int send_work(const char *hostname, int port, const char *filename)

{

// 连接到hostname指定的IP地址和port指定的断口

SOCKET st = socket_connect(hostname, port);

if (st == 0) // 连接失败,函数返回

{

return 0;

}

FILE *fd = fopen(filename, "rb"); // 以只读方式打开filename指定的文件

if (fd == NULL) // 如果打开文件失败,函数返回

{

printf("open %s failed %s\n", filename, strerror(errno));

return 0;

}

char *buf = malloc(BUFSIZE); // 申请一个缓冲区,存放接收到的文件内容

memset(buf, 0, BUFSIZE);

// 从完整路径名中解析出文件名称

getfilename(filename, buf);

size_t rc = send(st, buf, strlen(buf), 0); // 客户端第一次给server端发送的数据为要传递的文件名

if (rc <= 0)

{

if (rc < 0)

printf("send failed %s\n", strerror(errno));

else

printf("socket disconnect\n");

}

else

{

memset(buf, 0, BUFSIZE);

if (recv(st, buf, BUFSIZE, 0) <= 0) // 接受来自server端的回复

{

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("send failed %s\n", strerror(errno));

else

printf("socket disconnect\n");

break;

}

}

}

}

}

}

fclose(fd);

free(buf);

#ifdef WIN

close(st);

#endif

return 1;

}

SOCKET socket_create(int port)

{

if (init_socket() == -1)

return 0;

SOCKET st = socket(AF_INET, SOCK_STREAM, 0);

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 0;

}

struct sockaddr_in addr;

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

addr.sin_family = AF_INET;

addr.sin_port = htons(port);

addr.sin_addr.s_addr = htonl(INADDR_ANY);

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 %d success\n", port);

return st;

}

// server端socket开始accept的函数

SOCKET socket_accept(SOCKET listen_st)

{

struct sockaddr_in client_addr;

#ifdef WIN

int len = 0;

#else

unsigned int len = 1;

#endif

len = sizeof(client_addr);

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

// accept阻塞,知道有client连接到server才返回

SOCKET client_st = accept(listen_st, (struct sockaddr *)&client_addr, &len);

if (client_st == -1)

{

printf("accept failed %s\n", strerror(errno));

return 0;

}

else

{

printf("accept by %s\n", inet_ntoa(client_addr.sin_addr));

return client_st;// 有client连接到server,返回client的socket描述符

}

}

// server端socket在port指定的断口上listen,接收来自client发送的文件

int recv_work(int port)

{

// 建立server端socket,在port指定的端口listen

SOCKET listen_st = socket_create(port);

if (listen_st == 0) // 如果创建服务端socket失败,函数返回0

return 0;

// 如果有client连接到,socket_accept函数返回client的socket

SOCKET st = socket_accept(listen_st);

if (st == 0)

return 0;

char *buf = malloc(BUFSIZE);// 建立接收文件数据缓冲区

FILE *fd = NULL;

memset(buf, 0, BUFSIZE);

size_t rc = recv(st, buf, BUFSIZE, 0); // 接收来自client的数据,客户端第一次要发送的文件名称

if (rc <= 0)

{

if (rc < 0)

printf("recv failed %s\n", strerror(errno));

else

printf("socket disconnect\n");

}

else

{

printf("receiving %s\n", buf);

fd = fopen(buf, "wb");// 以只写方式打开文件

if (fd == NULL)

{

printf("open %s failed %s\n", buf, strerror(errno));

}

else

{

memset(buf, 0, BUFSIZE);

strcpy(buf, "OK");

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");

}

while (1)

{

memset(buf, 0, BUFSIZE);

rc = recv(st, buf, BUFSIZE, 0);// 循环接收来自client的数据,数据为发送文件的内容

if (rc <= 0)// 如果client连接断开,代表文件传递完成,或者网络意外中断,循环break

{

if (rc < 0)

printf("recv 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;

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值