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

By | 07月14日
Advertisement

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 <stdio.h>
#include <stdlib.h>
#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 <stdio.h>
#include <stdlib.h>
#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 <WinSock2.h>
#else
#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

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

Similar Posts:

  • linux scp 命令在两台主机之间文件传输

    参考:http://www.cnblogs.com/hitwtx/archive/2011/11/16/2251254.html scp命令: 不同的linux电脑之间进行文件的copy有三种方法: 第一种:ftp,也就是其中一台Linux安装ftp Server,这样可以另外一台使用ftp的client程序来进行文件的copy. 第二种:采用samba服务,类似Windows文件copy 的方式来操作,比较简洁方便. 第三种:利用scp命令来进行文件复制. 这里主要学习scp命令: scp是有

  • 在多台PC之间同步Resharper所有设置的方法

    默认情况下Resharper只允许导出CodeStyle的设置,对于其它的设置不能导出,这样在不利用我们在多台PC之间同步Resharper的设置,经过多次尝试和Google找到了一种解决办法: Resharper会将所有的设置保存到AppData目录下,只有拷贝并覆盖该设置目录就行了.设置的保存目录依系统可能会有所不同,例如在我的win7上就是在C:\Users\user\AppData\Roaming\JetBrains目录下.

  • Netcat所做的就是在两台电脑之间建立链接并返回两个数据流,在这之后所能做的事就看你的想像力了!

    netcat是网络工具中的瑞士军刀,它能通过TCP和UDP在网络中读写数据.通过与其他工具结合和重定向,你可以在脚本中以多种方式使用它.使用netcat命令所能完成的事情令人惊讶. netcat所做的就是在两台电脑之间建立链接并返回两个数据流,在这之后所能做的事就看你的想像力了.你能建立一个服务器,传输文件,与朋友聊天,传输流媒体或者用它作为其它协议的独立客户端. 下面是一些使用netcat的例子. [A(172.31.100.7) B(172.31.100.23)] Linux netcat

  • 两台服务器之间文件时时同步,哪个工具比较好使

    两台服务器之间文件时时同步,哪个工具比较好使 --cut-- RobinTang在1970-01-01 18:09:19回答到: 试试rsync YiXia在1970-01-01 02:13:23回答到: http://superuser.com/questions/317820/linux-continuously-synchronize-files-one-way 如果实时性没那么高,crontab + rsync可以考虑 Po_Lang在1970-01-01 11:51:10回答到: se

  • 两台笔记本电脑之间直接通过一条网线(双绞线)传输大文件教程(有图有真相)不需要有网

    两台笔记本电脑之间直接通过一条网线(双绞线)传输大文件教程(有图有真相)不需要有网 最近给女友买了一台电脑,想要把我的笔记本电脑的一些文件复制到女友的笔记本电脑上,用 U盘来当传输介质太麻烦,而且如果文件比U盘容量大的话更麻烦. 于是网络上寻找更好的办法,在百度知道里面了解到可以使用一条网线直接传输数据,但是网络上没有详细的教程,折腾好久也没能实现.最后问了搞开发的大牛 才解决了. 下面是主要两台电脑传输大文件的主要内容: 主要准备工作: (假设想要从A电脑复制文件到B电脑) 1.准备一条网线(

  • ROS(hydro)学习总结一:两台PC机间通信

    <ROS by Example Volume1>中,也讲过关于两台PC机间通信,但是其中过程太繁琐,并且如果按照书中讲解一步步操作,你将会发现并不能实现通信功能.对此,我对书中内容进行改进,给出可行的通信方案.此方案的实现环境是在装有ROS(hydro)的 Ubuntu12.04中. 两台PC机间通信(pc1和pc2),其中pc1为主控制机,pc2为被控制机,假设两pc主机名分别为pc1.pc2.(其中具体主机名以现实情况为准). pc1: 将以下语句添加进~/.bashrc中: export

  • 两台服务器之间的自动备份

    问题 1.两台服务器之间的自动备份的问题 如何实现两台服务器之间的自动备份是网管们经常遇到的问题. 比如:我们需要在夜间或服务器相对闲暇时,自动将服务器A中指定目录下的重要数据备份到服务器B中某个指定的目录中. 2.隔N天备份到不同目录的问题 有时,我们也可能遇到将服务器进行隔N天进行自动备份,同时又希望某一天的数据备份到另一个与上一天完全不同的目录中,这样,一旦万一出现某种错误,仍然可以做上一天的目录中恢复相关数据.这里讲的是"万一",不怕一万,就怕万一.安全第一呀,呵! 3.多服务

  • 在两台服务器之间建立信任关系解决scp,ssh等不用输入密码等问题

    引用地址: http://blog.chinaunix.net/u2/76835/showart.php?id=1359453 说明:蓝色文字为本人添加 最近在编写定时python脚本时遇到一个问题.在该脚本中,需要使用scp命令将本地的文件复制到另一台机器中备份.但通常执行scp命令后都需要输入用户密码,这样在定时自动执行的python脚步中就不适用了. 后来在Internet中查找相关资料,有资料[1]介绍在两台机器的两个用户之间建立安全的信任关系后,可实现执行scp命令时不需要输入用户密码

  • 两台centos之间传送文件

    最近在CentOS系统中(主机A)读数据.由于A主机只是作为数据读取,具体的Deep Learning 实验,需要在主机B( CentOS )中进行,需要将主机A上的数据传输.由于主机A并不是一直开着CentOS系统,且数据量比较(40G+),所以用优盘copy的方法有点不现实,经过查找资料,发现了两种方法. 注意:两台主机都是CentOS 6.5 版本的系统,主机A:IP 192.168.1.102 主机B:192.168.1.33 1.用命令行的方式 A,B 机上的SSH都允许root登录,

  • 两台路由器之间的串口互连

    有的时候在子公司和总公司之间距离不远的情况下可以直接用串口线将两台器串口连接起来.这种方法可以省去铺设光纤花费的费用,不过传输速度会受到一定的影响,而且两台路由器距离一定不能太远. 具体网络拓扑如图1所示,两台路由器A和B,用串口线分别连接各自的S0口. 配置命令: 路由器A config t 进入配置模式 int s0 进入S0接口 ip address 192.168.1.1 255.255.255.0 为S0接口设置IP地址和子网掩码 no shutdown 开启S0端口 clock ra

Tags: