📄 send_receive.c
字号:
/********************************************************** *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 + -