之前写过一篇文章,说明通过实现C/C++条件编译方式是实现水电站监控系统跨平台特性最合适的方式。这里我再补充说明其中的技术重点,其实也就是Unix/Linux与windows采用C/C++编程中需要注意的区别。
文件访问函数在不同的操作系统上存在一些行为细节方面的不同,如调用fread时候,windows上文件如果不用rb方式读取, 就会导致遇到空格的时候读取结束,而在Unix/Linux平台上不会出现。此外,在Unix/Linux上可以通过open函数打开文件后,通过read读取信息一般不会遇到问题,但在windows上采用相同调用方法,会发现明明文件中的内容还有很多read函数却没有按照调用入参中的长度限制返回最长的字符串,这可能是由于在windows上read函数中存在一个潜在的缓冲区限制。
IPC指的是Unix系统进程间访问,常用方式包括共享内存,消息队列和信号量。由于windows系统不支持这些功能,因此通过相近的功能替代。
Unix上共享内存的调用方式基本如下:
shm_id = shmget(SYS_DB_KEY, sizeof(SYS_DB)+i, 0666 | IPC_CREAT)
sysdb = (SYS_DB *)shmat(shm_id, (char *)0, 0)
但在windows上,不存在共享内存的机制,因此必须采用类似的技术代替,最简单的方式即文件映射内存,相同的代码段可以通过下面的方式修改:
sprintf(t_buf, "NCSYS_%d", SYS_DB_KEY);
HANDLE hFileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, sizeof(SYS_DB)+i, t_buf);
sysdb = MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
Unix环境下,消息队列的实现代码如下:
lan_msg_qid = msgget (LAN_CLIENT_MSG_KEY,0600)
msgsnd (lan_msg_qid,&init_msg,sizeof(init_msg),0))
由于windows上也不存在消息队列,因此采用其他技术实现,比如邮槽,上述代码可以通过下面的方式进行修改:
sprintf(servername, "\\\\.\\Mailslot\\%lld", LAN_CLIENT_MSG_KEY);
lan_mailslot_handle = CreateFile(servername, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)
WriteFile(lan_mailslot_handle, &init_msg, sizeof(init_msg),&BytesWritten, NULL)
Unix下,信号量的实现代码如下:
1) 初始化:
lan_semid = semget(LAN_SEM_KEY,1, 0600| IPC_CREAT | IPC_EXCL))
2) P操作:
structsembuf sops[1];
sops[0].sem_num = SEM_NUM;
sops[0].sem_op = GET;
sops[0].sem_flg = 0;
semop(lan_semid, sops, 1))
3) V操作:
structsembuf sops[1];
sops[0].sem_num = SEM_NUM;
sops[0].sem_op = RELEASE;
sops[0].sem_flg = 0;
semop(lan_semid, sops, 1)
信号量在windows操作系统中也存在,但是用法和含义与linux和Unix不同,这里按照windows信号量的用法改写代码,具体代码修改方式如下:
1) 初始化:
lan_semid = CreateSemaphore(NULL, 0, 1, NULL);
2) P操作:
while(WaitForSingleObject(lan_semid,INFINITE) != WAIT_OBJECT_0);
3) V操作:
ReleaseSemaphore(lan_semid,1,NULL);
网络访问在windows操作系统中也存在,但是用法与linux和Unix不同,这里按照windows网络访问的用法改写代码。
DWORD NumberOfBytesRead;
OVERLAPPED ov;
ov.Offset = 0;
ov.OffsetHigh = 0;
ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);