TCP UDP 同步数据

前段时间自己在写一个基于TCP/UDP的文件传输小程序,就是客户端输入文件名之后服务器能够接收。

开始由于没有构思很仔细,在传递文件信息和文件内容的时候总是不能够很成功,因为第一次传送的是文件信息,但是之后传送的是文件的内容,就是这两步区分不是很好,之后还是突然经过一帅哥提醒了一下,发现在TCP中客户端第一次可以发送文件信息,于是自己创建了一个结构体:

/** @struct fileInfo
 *  @brief file information, file name and file size
 */

struct fileInfo                  // file information
{
    char fileName[FILENAMESIZE];
    unsigned long fileSize;
};

之后通过强制转换为(char *)类型传递给服务器端,

if( send(sockfd, (char *)fileInfo, sizeof(struct fileInfo), 0) < 0 ) 
    {
        printf("send file information error!\n");
        exit(1);
    }    

之后服务器端强制转换为(struct fileInfo *)类型获取对应的消息内容

recvNum = recv(connfd, buff, MAXBUF, 0);    //receive data from client
tmp = (struct fileInfo *)buff;

之后服务器再发送一个确认信息:

strcpy(buff, "SUCCESS");
            if( send(connfd, buff, sizeof(buff), 0) < 0 ) 
            {
                printf("tcp: send error!\n");
                exit(1);
            }

再之后客户端收到确认信息

recv(sockfd, buf, MAXBUF, 0);     // receive confirm message
        if ( strcmp(buf, "SUCCESS") != 0 )
        {
            printf("receive confirm message error!\n");
            exit(1);
        }

经过这一段的交互,之后就可以通过send()和recv()发送读取文件内容。

这样就实现了文件的传递。


之后自己在UDP中也打算使用这个机制,发现由于UDP不是可靠的连接,你不能保证你第一次发送的文件头信息服务器就能够收到,于是纠结了好久,最后发现了另外一种可以实现的方法:

就是同样定义一个结构体,

/** @struct udpMsg
 *  @brief file information and a synchronize flg used to synchronize server and client
 */
struct udpMsg                    // udp message to synchronous the data
{
    struct fileInfo fileInfo;
    int SynFlg;
};

但是其中包含了一个flg,初始化为0,之后服务器端收到文件之后读取flg的值看是否为0,如果是表示传送的文件头信息,如果不是表示接收到的是文件内容信息,之后就可以通过文件读写操作来实现文件的接收了,就完成了文件的传送。并且还使用了select()阻塞的监听客户端的请求,部分代码如下:

 printf("======UDP:waiting for client's request======\n");   
    while (1)
    {
        tv.tv_sec = 10;
        tv.tv_usec = 0;


        FD_ZERO(&rdset);
        FD_ZERO(&writeset);
        FD_SET(sockfd, &rdset);
        FD_SET(sockfd, &writeset);
        
        ret = select(sockfd + 1, &rdset, &writeset, NULL, &tv);
        if (-1 == ret)
        {
            printf("udp: select error!\n");
            exit(1);
        }
        else if (0 == ret)
        {
            //printf("udp: select timeout, continue...\n");
            continue;
        }


         if (FD_ISSET(sockfd, &rdset))    // socket is readable, then we read
         {
             printf("udp: server first read udpMsg->SynFlg = %d\n", udpMsg->SynFlg);
             if ( 0 == udpMsg->SynFlg )     // means it is the first time we get the msg, the msg is file infomation
             {
                 readSize = read(sockfd, buf, MAXBUF);
                 printf("udp: receive num: %d\n", readSize);
                 
                 tmp = (struct udpMsg *)buf;
                 strcpy(udpMsg->fileInfo.fileName, tmp->fileInfo.fileName);
                 udpMsg->fileInfo.fileSize = tmp->fileInfo.fileSize;
                 udpMsg->SynFlg = tmp->SynFlg + 1;
                 printf("udp: fileSize = %lu, SynFlg = %d\n", udpMsg->fileInfo.fileSize, udpMsg->SynFlg);
 
                 if ( (fd = open(udpMsg->fileInfo.fileName, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1 ) // create the file
                 {
                printf("udp: create error\n");                   
                exit(1);
            }
                 printf("udp: create file succeed!\n");
                 
             }
             else              // it is file content ,we just read and write to file
             {
                 while ( (readSize = read(sockfd, buf, MAXBUF)) > 0 )
                 {
                     int tmp = 0;
                     //printf("udp: read client data: %s\n", buf);
                     fileSize += readSize;
                     //printf("udp: read file size = %lu\n", fileSize);
                     if ( (tmp = write(fd, buf, readSize)) != readSize )
                     {
                         //(write(fd, buff, recvNum)
                         printf("udp: write data:%d\n", tmp);
                         printf("udp: received file error!\n");
                         exit(1);
                     }   
                 }


                 if ( fileSize == udpMsg->fileInfo.fileSize )
                 {
                     printf("udp: received file success!");
                 }
                 
             }


        }
    }


ps:最初自己udp使用的是sendto和recvfrom,发现这两个函数用的巨蛋疼,而且还是五个参数,期间还发现了莫名其妙的错误,可能也是自己不熟悉的原因,之后自己就先通过connect()连上服务器,后面的操作就通过read(),write()函数来发送数据,轻松了很多...

代码如下:

void connectUDP(struct udpMsg *udpMsg, int sockfd, struct sockaddr *serveraddr, socklen_t servlen)
{
   .......
    if ( -1 == (connect(sockfd, serveraddr, servlen)) )
    {
        printf("UDP connect error!\n");
        exit(1);
    }

......

}

程序截图如下:


以上东西也是自己的心得,发现遇到问题然后解决感觉还是挺舒服的,也希望对大家能够有所帮助...


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值