1、传输文件时读取标准输入:暂停、停止
void *thread_function(void)
{
fd_set m_fdset; //待检查文件的描述符
struct timeval timeout = {1, 0}; //设置超时时间为1秒
//用select超时实现非阻塞读取标准输入
while(1)
{
//select函数不会修改timeout的值,所以每次循环都应该重新赋值
timeout.tv_sec = 1;
timeout.tv_usec = 0;
if(FILE_STATE_START == m_filestate)
{
FD_ZERO(&m_fdset); //清空m_fdset变量
FD_SET(STDIN_FILENO, &m_fdset);//设置为标准输入
switch(select(STDIN_FILENO+1, &m_fdset, NULL, NULL, &timeout))
{
//出错
case -1:
perror("select");
break;
//超时
case 0:
break;
//发生状态变化的文件描述符的个数
default:
if(FD_ISSET(STDIN_FILENO, &m_fdset))
{
char ch = fgetc(stdin);
//文件传输暂停
if(FILE_TRANS_PAUSE == atoi(&ch))
{
m_filestate = FILE_STATE_PAUSE;
}
//文件传输停止
else if(FILE_TRANS_STOP == atoi(&ch))
{
m_filestate = FILE_STATE_STOP;
}
}
break;
}
}
else
{
//没有传输文件,线程休眠
sleep(1);
}
}
}
2、主函数
int main(int argc, char *argv[])
{
int sockfd = -1;
int sockerr = 0;
int socklen = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr;
//文件传输相关
int retval = 0; //文件传输返回字节数
int torecv = 0; //剩余要接收的文件大小
char buf[BUFFER_SIZE] = {0};
FILE *fp = NULL;
protocol m_protocol; //协议结构体
server_config m_config; //服务器配置结构体
file_info m_fileinfo; //传输文件信息结构体
memset(&m_fileinfo, 0, sizeof(file_info));
pthread_t thread_handle = 0; //线程句柄
//创建一个线程在文件传输时接收标准输入
if(pthread_create(&thread_handle, NULL, (void*)thread_function, NULL) != 0)
{
perror("pthread_create");
return -1;
}
//创建一个套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
perror("socket");
return -1;
}
//配置服务器地址与端口
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(SOCKET_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
//连接服务器
if(connect(sockfd, (struct sockaddr*)&server_addr, socklen) == -1)
{
perror("connect");
close(sockfd);
return -1;
}
while(!sockerr)
{
char ch[100] = {0};
memset(&m_protocol, 0, sizeof(protocol));
printf("***********************n"
"1:Get file list *n"
"2:Get server config *n"
"3:Set server config *n"
"4:Start file trans *n"
"5:Start file trans *n"
"6:Start file trans *n"
"***********************n");
printf("Please input command:");
scanf("%s", ch);
m_protocol.cmd = ch[0] - '0';
//对异常输入进行判断
if(m_protocol.cmd < 1 || m_protocol.cmd > 6 || ch[1] != 0)
{
printf("The command is invalid!n");
}
else
{
switch(m_protocol.cmd)
{
//获取文件列表
case GET_FILE_LIST:
if(-1 == write(sockfd, (char*)&m_protocol, sizeof(protocol)))
{
perror("write");
sockerr = 1;
}
memset(buf, 0, BUFFER_SIZE);
//当socket链接中断时会返回0,read错误时返回-1
if(read(sockfd, buf, BUFFER_SIZE) <= 0)
{
perror("read");
sockerr = 1;
break;
}
else
{
printf("%s", buf);
}
break;
//获取服务器配置参数
case GET_SER_CONFIG:
if(-1 == write(sockfd, (char*)&m_protocol, sizeof(protocol)))
{
perror("write");
sockerr = 1;
}
memset(&m_config, 0, sizeof(server_config));
//当socket链接中断时会返回0,read错误时返回-1
if(read(sockfd, (char*)&m_config, sizeof(server_config)) <= 0)
{
perror("read");
sockerr = 1;
break;
}
else
{
printf("name:%sclient_max:%dn", m_config.name, m_config.clieng_max);
}
break;
//设置服务器配置参数
case SET_SER_CONFIG:
printf("Please input server name:");
scanf("%s", m_protocol.name);
printf("Please input the max number of server:");
scanf("%d", &m_protocol.length);
if(-1 == write(sockfd, (char*)&m_protocol, sizeof(protocol)))
{
perror("write");
sockerr = 1;
}
//获取服务器配置的结果
if(read(sockfd, (char*)&m_config, sizeof(server_config)) <= 0)
{
perror("read");
sockerr = 1;
}
else
{
if(!xtrcmp(m_protocol.name, "")
{
printf("Set server config failed!");
}
else
{
printf("Set server config success!n");
printf("name:%snclient_max:%dn", m_config.name, m_config.client_max);
}
}
break;
//文件开始传输
case FILE_TRANS_START:
if(torecv > 0)
{
strncpy(m_protocol.name, m_fileinfo.name, NAME_LEN);
printf("FILE name:%sn", m_protocol.name);
}
else
{
printf("Please input file name:");
scanf("%s", m_protocol.name);
}
if(-1 == write(sockfd, (char*)&m_protocol, sizeof(protocol)))
{
perror("write");
sockerr = 1;
}
//接收服务器的回复,判断是否满足文件传输的条件
memset(&m_protocol, 0, sizeof(protocol));
if(read(sockfd, (char*)&m_protocol, sizeof(protocol)) <= 0)
{
perror("read");
sockerr = 1;
}
else
{
if(strcmp(m_protocol.name, "") != 0)
{
if(torecv > 0)
{
//继续传输旧文件,以附加的方式打开只写文件
fp = fopen(m_protocol.name, "a")
}
else
{
//传输新文件
torecv = m_protocol.length;
fp = fopen(m_protocol.name, "w");
}
if(NILL == fp)
{
perror("fopen");
}
else
{
printf("Start receiving file!n");
m_filestate = FILE_STATE_START;
while((retval = read(sockfd, buf, sizeof(buf))) > 0)
{
fwrite(buf, 1, retval, fp);
memset(buf, 0, sizeof(buf));
//计算剩余字节数
torecv -= retval;
if(torecv <= 0)
{
printf("FILE:%s receive success!n", m_protocol.name);
//清除文件信息
torecv = 0;
memset(&m_fileinfo, 0, sizeof(file_info));
m_filestate = FILE_STATE_STOP;
if(write(sockfd, (char*)&m_protocol, sizeof(protocol)) < 0)
{
perror("write");
sockerr = 1;
}
break;
else
{
//暂停传输
if(FILE_STATE_PAUSE == filestate)
{
strncpy(m_fileinfo.name, m_protocol.name, NAME_LEN);
printf("FILE_TRANS_PAUSE!n"
"Left:%dn", torecv);
//发送暂停命令
memset(&M-protocol, 0, sizeof(protocol));
m_protocol.cmd = FILE_TRANS_PAUSE;
if(write(sockfd, (char*)&m_protocol, sizeof(protocol)) < 0)
{
perror("write");
sockerr = 1;
}
break;
}
//停止传输
else if(FILE_STATE_STOP == m_filestate)
{
torecv = 0;
memset(&m_fileinfo, 0, sizeof(file_info));
printf("FILE_TRANS_STOP!n");
//发送停止命令
m_protocol.cmd = FILE_TRANS_STOP;
if(write(sockfd, (char*)&m_protocol, sizeof(protocol)) < 0)
{
perror("write");
sockerr = 1;
}
break;
}
else
{
if(write(sockfd, (char*)&m_protocol, sizeof(protocol)) < 0)
{
perror("write");
sockerr = 1;
}
}
}
}
fclose(fp);
fp = NULL;
}
}
else
{
printf("File not exist!n");
}
}
break;
//文件暂停传输
case FILE_TRANS_PAUSE:
//指令在线程中读取
if(m_filestate != FILE_STATE_START)
{
printf("No file is transferring!n");
}
break;
//文件停止传输
case FILE_TRANS_STOP:
//指令在线程中读取
if(m_filestate != FILE_STATE_START)
{
printf("No fole is transferring!n");
}
break;
default:
break;
}
}
}
close(sockfd);
return 0;
}



