新人作业之基于TCP连接,用消息队列实现图片发送功能,

具体要求是:
1、客户端接受图片,服务器发送图片,建立TCP 连接
2、每次有客户端过来,服务器创建一个线程单独实现图片发送功能
3、最多5个客户端同时连接服务器,超过5个就会失败
4、服务器本地存储一张图片,在服务器处输入“start”之后,服务器就开始向在线的客户端发送图片
5、客户端收到图片之后,保存到一个目录中,目录名是年月日,文件名为时分秒

简单来说:就是服务器向客户端发送图片。。。。。。。看起来很简单,我在具体实现的过程中踩了几个大坑:

1、以前在学校学习的时候学的是msgget,msgsnd,msgrcv这些System V标准下的消息队列,哪知道现在参加工作之后,又有了POSIX标准下的消息队列。在开始的选择的时候,也考虑过选什么(其实我两个的版本都写了)。

基于服务器要向在线的客户端发送图片,即相当于实现一个群发功能,我还是选择了System V标准的消息队列。两个有个区别就是,POSIX下的收发函数有个参数是优先级,我在发送的时候,设置了一个优先级,然后recv函数那里收到的优先级是一样的,而SystemV标准的函数可以设置固定位置的消息类型

2、服务器在向客户端发送图片的时候,客户端处接受的图片会失真
新人作业之基于TCP连接,用消息队列实现图片发送功能,_第1张图片

然后通过打印客户端和服务器那边的数据发现,大小也没有差很多,在网上查了很久,也没有人遇到这个问题,后来,无意间看到对消息队列中 对下面这个结构体的解释
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);
}

你可能感兴趣的:(C语言,linux,c,网络编程)