具体要求是:
1、客户端接受图片,服务器发送图片,建立TCP 连接
2、每次有客户端过来,服务器创建一个线程单独实现图片发送功能
3、最多5个客户端同时连接服务器,超过5个就会失败
4、服务器本地存储一张图片,在服务器处输入“start”之后,服务器就开始向在线的客户端发送图片
5、客户端收到图片之后,保存到一个目录中,目录名是年月日,文件名为时分秒
简单来说:就是服务器向客户端发送图片。。。。。。。看起来很简单,我在具体实现的过程中踩了几个大坑:
1、以前在学校学习的时候学的是msgget,msgsnd,msgrcv这些System V标准下的消息队列,哪知道现在参加工作之后,又有了POSIX标准下的消息队列。在开始的选择的时候,也考虑过选什么(其实我两个的版本都写了)。
基于服务器要向在线的客户端发送图片,即相当于实现一个群发功能,我还是选择了System V标准的消息队列。两个有个区别就是,POSIX下的收发函数有个参数是优先级,我在发送的时候,设置了一个优先级,然后recv函数那里收到的优先级是一样的,而SystemV标准的函数可以设置固定位置的消息类型
2、服务器在向客户端发送图片的时候,客户端处接受的图片会失真
然后通过打印客户端和服务器那边的数据发现,大小也没有差很多,在网上查了很久,也没有人遇到这个问题,后来,无意间看到对消息队列中 对下面这个结构体的解释
struct msgbuf {
long mtype; /* message type, must be > 0 /
char mtext[1]; / message data */
};
就是自己的定义的时候,第一个参数一定是mtype,之后的可以随你写,大小就是这个结构体除type之外的大小!!!
其实就是在调用
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
填写msgsz这个参数的时候,直接写 sizeof(msg)-sizeof(long)就可以了
3、这个其实和第一个差不多,就是在实现群发功能的时候,消息类型的设定问题,它这个一定可以区分出不同客户端的一个值,这样不同的客户端在接受时才能都完整的接收到,否则的话,就会出现几个客户端一同获取同一个消息类型
前面的TCP连接就不说了,主要针对上面几点来看代码:
1、接受发送函数的设置
我的msg设置是:
struct msg_dt
{
long int msgtype;
pid_t pid;
int len;
char buf[BUFSIZE];//发送图片信息
};
发送:
status = msgsnd(msgid,(void *)&msg,sizeof(msg)-sizeof(long),0);
if(status < 0)
{
perror("msgsnd error");
exit(EXIT_FAILURE);
}
接受:
msgrcv(msgid,(void *)&msg,sizeof(msg)-sizeof(long),0,0);
接受函数的消息类型这边设置0,可以接受消息队列中的第一个消息类型
2、群发过程中消息类型的设置:
客户端:(将当前进程的pid发送给服务器,服务器收到之后,设置为消息类型)
msg.msgtype = 1;
status = msgsnd(msgid,(void *)&msg,sizeof(msg)-sizeof(long),0);
if(status < 0)
{
perror("msgsnd error");
exit(EXIT_FAILURE);
};
服务器端:
//获取客户端的pid号
msgrcv(msgid,(void *)&msg,sizeof(msg)-sizeof(long),0,0);
msg.msgtype = msg.pid;//将客户端的pid号设置成消息类型
online[num] = msg.pid;//存储在线的客户端信息
之后服务器发送图片信息:
while(1)
{
len = fread(msg.buf,1,sizeof(msg.buf),fp);
status = msgsnd(msgid,(void *)&msg,sizeof(msg)-sizeof(long),0);
if(status < 0)
{
perror("mq_send error");
exit(EXIT_FAILURE);
}
if(len == 0)
{
printf("fread over\n");
break;
}
sleep(1);
}
客户端接受:
nbytes = msgrcv(msgid,(void *)&msg,sizeof(msg)-sizeof(long),getpid(),0);
if(nbytes < 0)
{
perror("msgrcv error:\n");
exit(EXIT_FAILURE);
}