⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 send_receive.c

📁 飞鸽传书协议的linux实现,使用多线程实现的
💻 C
📖 第 1 页 / 共 2 页
字号:
/********************************************************** *Filename: send_receive.c *Author:   蔡业桂 *Date:     2009-5-21 * *消息、文件(夹)的发送和接收 *********************************************************/#include "send_receive.h"#include "ipmsg.h"#include "users.h"#include "coms.h"#include <sys/utsname.h>#include <string.h>#include <sys/stat.h>#include <sys/types.h>#include <dirent.h>#include <errno.h>#include <pwd.h>#include <sys/utsname.h>#include <signal.h>#include <pthread.h>////////////////////////////////////////////////////发送udp包void* sendMsg(command* com){  char buf[COMLEN];  int len, temp;    msgCreater(buf, com, sizeof(buf));  len = strlen(buf);  if (com->commandNo & IPMSG_FILEATTACHOPT)    {      temp = strlen(buf+len+1);            sendto(msgSock, buf, len+temp+2, 0,             (struct sockaddr*)&com->peer, sizeof(com->peer));     }  else sendto(msgSock, buf, len+1, 0,              (struct sockaddr*)&com->peer, sizeof(com->peer));}////////////////////////////////////////////////////聊天int saySth(){  char buf[100]; //临时输入区  char gMsg[MSGLEN];  command com;  user *cur=NULL;  int remainder; //扩展区剩余空间  int pos;       //扩展区的当前输入位置  int who, temp, count;  int sended;      //标记此包是否已经发过  user *pusers[50];  printf("\n*Talking mode\n"         "*Continuous Enter to send msg,\n"         "*Ctrl+D to quit conversation.\n");    pthread_mutex_lock(&usrMutex);  count = listUsers(pusers, &userList, sizeof(pusers)/sizeof(pusers[0]), 0);  pthread_mutex_unlock(&usrMutex);    who = inputNo(1, count, 1, "Please input user No.[1]:");    if (who>0)  {    cur = pusers[who-1];        initCommand(&com, IPMSG_SENDMSG|IPMSG_SENDCHECKOPT);    memcpy(&com.peer, &cur->peer, sizeof(com.peer));        remainder = MSGLEN;    pos = 0;    sended = 1;        while(1)    {      printf("(talking with %s):", cur->name);      if (fgets(buf, sizeof(buf), stdin)==NULL)        break;      if (buf[0] != '\n')      {        strncpy(com.additional+pos, buf, remainder);        temp = strlen(com.additional+pos);        pos += temp;        remainder -= temp;        sended = 0;      }      if ((buf[0]=='\n') || (remainder<=1))      {        if (!sended)        {          com.packetNo = (unsigned int)time(NULL);          sendMsg(&com);          sended = 1;          printf("Message sent.\n");        }        remainder = sizeof(com.additional);        pos = 0;      }          }  }      puts("\nEnd conversation.\n");        pthread_mutex_lock(&usrMutex);    unListUsers(pusers, count);    pthread_mutex_unlock(&usrMutex);  }///////////////////////////////////////////////////文件发送//选择要传输的文件int selectFiles(){  command com;  user *cur=NULL;  int  who, count, flag, fileType;  unsigned int fileNo;  char fileName[FILENAME];  struct stat fileAttr;  char *strtmp;  filenode *fntmp, *head, *tail;  gsNode *newTask;  user *pusers[50];    printf("\n*Sending mode\n"         "*Continuous Enter to send file,\n"         "*Ctrl+D to quit.\n");    pthread_mutex_lock(&usrMutex);  count = listUsers(pusers, &userList, sizeof(pusers)/sizeof(pusers[0]), 0);  pthread_mutex_unlock(&usrMutex);  who = inputNo(1, count, 1, "Please input user No.[1]:");  if (who>0)  {        cur = pusers[who-1];      initCommand(&com, IPMSG_SENDMSG|IPMSG_FILEATTACHOPT);    memcpy(&com.peer, &cur->peer, sizeof(com.peer));        printf("To send file to %s(%s).\nPlease select file to send:\n", cur->name, cur->host);        newTask = (gsNode*)malloc(sizeof(gsNode));    initGsNode(newTask);    newTask->packetNo = com.packetNo;        fileNo = 0;    head = com.fileList;    tail = com.fileList;        while (1)    {      if (fgets(fileName, FILENAME, stdin) == NULL) //取消传输      {        free(newTask);        newTask = NULL;        while (head!=NULL)        {          tail = head;          head = head->next;          free(tail);        }        break;      }       transfStr(fileName, 0); //去除前后空白字符             if (fileName[0]=='\0')        break;           if (lstat(fileName, &fileAttr)<0)      {        printf("Get file attributes error.\n");        continue;      }      if (S_ISREG(fileAttr.st_mode))        fileType = 1;      else if (S_ISDIR(fileAttr.st_mode))        fileType = 2;      else      {        fileType = -1;        printf("Unsupported file type.\n");        continue;      }            if (tail == NULL)        head = tail = (filenode*)malloc(sizeof(filenode));      else      {        tail->next = (filenode*)malloc(sizeof(filenode));        tail = tail->next;      }            tail->next = NULL;      tail->fileNo = fileNo;      strncpy(tail->fileName, fileName, sizeof(tail->fileName));      snprintf(tail->fileSize, sizeof(tail->fileSize), "%x", fileAttr.st_size);      snprintf(tail->mtime, sizeof(tail->mtime), "%x", fileAttr.st_mtime);      tail->fileType = fileType;      fileNo++;    }        if (head==NULL)    {      if (newTask!=NULL)        free(newTask);    }    else     {      newTask->fileList.next = com.fileList = head;      pthread_mutex_lock(&sendFMutex); //lock      newTask->next = sendFHead.next;      sendFHead.next = newTask;      pthread_mutex_unlock(&sendFMutex); //unlock      if (newTask->fileList.next!=NULL)      {        sendMsg(&com); //可以放lock外面        printf("\nWaiting to transfer.\n");      }    }  }  pthread_mutex_lock(&usrMutex);  unListUsers(pusers, count);  pthread_mutex_unlock(&usrMutex);  }//文件或文件夹发送void* sendData(void* option){  int fSock = *(int *)option;  char buf[RECFRG], fileName[FILENAME];  int i, commandNo, realCount, offset, curErr;  unsigned int packetNo, fileNo;  filenode *preFile, *curFile;  gsNode *preSend, *curSend;  FILE* sfile;  sigset_t mask, oldmask;  free(option);    sigemptyset(&mask);  sigaddset(&mask, SIGPIPE);  if (pthread_sigmask(SIG_BLOCK, &mask, &oldmask) != 0)    printf("SIG_BLOCK error.\n");    //以tcp的方式接受传输请求  for (i=0;i<4;i++)  {    if (readDelimiter(fSock, buf, RECFRG, ':')<=0)    {      printf("Transfer cancelled.\n");      shutdown(fSock, SHUT_RDWR);      return NULL;    }    }  if (readDelimiter(fSock, buf, RECFRG, ':')<=0)  {    printf("Transfer cancelled.\n");    shutdown(fSock, SHUT_RDWR);    return NULL;  }    commandNo = atoi(buf);  if (!(commandNo & IPMSG_GETFILEDATA))  {    printf("Invalid request.\n");    shutdown(fSock, SHUT_RDWR);    return NULL;  }      if (readDelimiter(fSock, buf, RECFRG, ':')<=0)  {    printf("Transfer cancelled.\n");    shutdown(fSock, SHUT_RDWR);    return NULL;  }    sscanf(buf, "%x", &packetNo);  if (readDelimiter(fSock, buf, RECFRG, ':')<0)  {    printf("Transfer cancelled.\n");    shutdown(fSock, SHUT_RDWR);    return NULL;  }  sscanf(buf, "%x", &fileNo);  pthread_mutex_lock(&sendFMutex);    preSend = &sendFHead;  curSend = sendFHead.next;  while ((curSend != NULL) &&         (curSend->packetNo!=packetNo || curSend->transferring==1 ||         curSend->cancelled==1)){    preSend = preSend->next;    curSend = curSend->next;  }    if (curSend != NULL)  {    curSend->transferring = 1;    curSend->tcpSock = fSock;    pthread_mutex_unlock(&sendFMutex);        curFile = curSend->fileList.next;    preFile = &curSend->fileList;    while ((curFile!=NULL) && (curFile->fileNo!=fileNo))    {      preFile = preFile->next;      curFile = curFile->next;    }        if (curFile != NULL)    {      getFileName(fileName, curFile->fileName, sizeof(fileName));      printf("\nStart transferring %s.\n", fileName);      switch (curFile->fileType)      {      case 1: //发送文件        if (readDelimiter(fSock, buf, RECFRG, ':')<=0) //offset似乎没用上        {          printf("Transfer cancelled.\n");          shutdown(fSock, SHUT_RDWR);          return NULL;        }        sscanf(buf, "%x", &offset);                sfile = fopen(curFile->fileName, "r");                while ((realCount = fread(buf, 1, RECFRG, sfile))>0)          if (writen(fSock, buf, realCount)<0)          {            curErr = errno;            break;          }        break;      case 2: //发送文件夹        curErr = traverseDir(fSock, curFile->fileName, sendDir);         break;      default:        break;      }    }  }  else pthread_mutex_unlock(&sendFMutex);  pthread_mutex_lock(&sendFMutex);  if ((curSend!=NULL) && (curSend->cancelled==1))  {    preSend->next = curSend->next;    deGsNode(curSend);    free(curSend);    pthread_mutex_unlock(&sendFMutex);    shutdown(fSock, SHUT_RDWR);    printf("Transfer canceled.\n");    return NULL;  }    if ((curErr<0) || (errno == ECONNRESET) || (errno == EPIPE)) //error or connection reset by peer  {    if (curFile!=NULL)    {      curSend->transferring = 0;      curSend->tcpSock = -1;    }    pthread_mutex_unlock(&sendFMutex);    shutdown(fSock, SHUT_RDWR);    printf("Peer needs retransfer.\n");    return NULL;  }    if (curFile!=NULL)  {    printf("\n%s is transferred.\n", fileName);    preFile->next = curFile->next;    free(curFile);  }      if (curSend!=NULL && curSend->fileList.next == NULL)  {    preSend->next = curSend->next;    deGsNode(curSend);    free(curSend);  }  else if (curSend!=NULL)  {    curSend->transferring = 0;    curSend->tcpSock = -1;  }  pthread_mutex_unlock(&sendFMutex);    shutdown(fSock, SHUT_RDWR);}//发送文件夹int sendDir(int fSock, const char* fullpath, int fileSize, int fileType){  char strtmp[FILENAME], strformat[50], strdata[RECFRG], fileName[FILENAME];  int tmp, headLen, packetNo;  FILE *sf;  if (getFileName(strtmp, fullpath, sizeof(strtmp)) < 0)  {    printf("\nFilename is too long.\n");    return -1;  }  addColon(strtmp, sizeof(strtmp));  if (utf8)    u2g(strtmp, sizeof(strtmp),        fileName, sizeof(fileName));  else strncpy(fileName, strtmp, sizeof(fileName));    headLen = (strlen(fileName)+1) + (HL_HEADERSIZE+1) +    (HL_FILETYPE+1) + (HL_FILESIZE+1) + 2*(HL_1416+1);  packetNo = (unsigned int)time(NULL); //简化了,属性值并不准确  snprintf(strformat, sizeof(strformat), "%%0%dx:%%s:%%0%dx:%%0%dx:14=%%0%dx:16=%%0%dx:",           HL_HEADERSIZE, HL_FILESIZE, HL_FILETYPE, HL_1416-3, HL_1416-3);    tmp = snprintf(strdata, sizeof(strdata), strformat,           headLen, fileName, fileSize, fileType, packetNo, packetNo);    switch (fileType)  {  case 1:    if ((sf = fopen(fullpath, "r")) == NULL)    {      printf("file open error.\n");      return -1;    }    if (writen(fSock, strdata, tmp)<0)      return -1;    while ((tmp = fread(strdata, 1, RECFRG, sf))>0)    {      if (writen(fSock, strdata, tmp)<0)        return -1;    }    fclose(sf);    break;  case 2:       //break;  case 3:    if (writen(fSock, strdata, tmp)<0)      return -1;    break;  default:    break;  }  return 0;}//遍历要发送的文件夹,利用上面的回掉函数发送int traverseDir(int fSock, char* fullpath, Mysnd snd) //FILENAME指定了fullpath的容量{  struct stat fst;  struct dirent *dirp;  char *ptr;  DIR  *dp;  int tmp;    if (lstat(fullpath, &fst)<0)  {    printf("\nDir: get attributes error.\n");    return -1;  }    if (S_ISREG(fst.st_mode))    return snd(fSock, fullpath, fst.st_size, 1);  else if (S_ISDIR(fst.st_mode))  {    if (snd(fSock, fullpath, 0, 2)<0)      return -1;  }  else return -1;  tmp = strlen(fullpath);  ptr = fullpath + tmp;    *ptr++ = '/'; //tmp+1  *ptr = '\0';  if ((dp=opendir(fullpath)) == NULL)  {    printf("\nDir: open error.\n");    return -1;  }  while ((dirp=readdir(dp)) != NULL)  {    if (strcmp(dirp->d_name, ".")==0 ||        strcmp(dirp->d_name, "..")==0)      continue;    strncpy(ptr, dirp->d_name, FILENAME-tmp-1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -