项目介绍:服务器Linux,客户端Windows,实现类似于QQ的功能
注释:部分仍然是疑惑
1. 定义了一个消息头,格式如下
//消息头 typedef struct MsgHead { char cSenderName[16]; char cRecverName[16]; int iMsgType; int msglen; char * data() { return (char *)(this+1); } }MsgHead, *pMsgHead;
接收到消息时,拷贝内存的时候忘了把data(),也就是头部后面的内容拷贝过去;
实践证明,在char * 和结构体之间转换是安全的!
2.在一个线程中,定义了一段内存用来接收消息,假设为recvBuf[1024],之后调用处理函数handleMsg(const char * data, int dataLen)对其进行处理。但是出现了内存释放错误,分析原因:recvBuf中使用了const进行限定,所以当新的消息到来时,handleMsg()函数无法释放该段内存,导致出错。
3.多个线程访问同一个数据结构,用互斥锁时,出现死锁;但不用互斥锁时,线程A删除了某个元素,而线程B正好要去访问这个元素,内存访问出错,导致主线程自动退出?一点错误提示都没有??疑惑
4.在编写客户端时,有时候会出现内存访问错误。然后把代码遛了一圈,发现没有野指针什么的呀...而且该问题忽有忽无,感觉像是多线程引起的问题。果不其然,客户端用一段缓存来存放收到的数据,一旦消息传过来的比较多,处理不及的话导致的。主要原因在于,用AfxMessageBox()函数来做调试用,但也导致信息处理的暂停。注释掉AfxMessageBox()之后,问题不在。
5.客户端是用MFC实现的(比较老的东西了,估计大家都不用了)。在发送方发送消息之后,接收方接收到的消息都有乱码。以为是中间传参数的时候,字符数组跟指针复制的时候有问题,然后用strcpy()代替memcpy(),这样就只拷贝‘\0’之前(包括'\0')的有效字符了。但两头来回查,始终存在乱码问题。
后来突然想起来,在MFC下的CString类型的GetLength()函数好像是只取不包括'\0'的有效字符的,这样传递过去的时候,就会因为找不到截至符而出现乱码!
CString.GetLength()+1之后成功解决该问题。
6.关于字符数组跟指针。字符数组我在使用之前一般都用内存设置函数memset()使里面的字符全为0,这样当内存拷贝时,确定无疑会有终结符,属于比较保险的操作;但是,字符类型的指针就不同了,它一般都在有效字符后加终结符'\0',之后可能是其他内容。所以,在使用这两者时,还是尽量用字符类型的函数,如strcmp(),strcpy()等。我个人原先比较青睐内存操作函数,可能会出现一些问题。
比如 char * pName="china",char cName[16]={0}, memcpy(cName, "china", 16);
当用memcmp()函数进行比较时,就会出现结果不为0的情况;而如果使用strcmp()函数进行比较,结果则为0;因为strcmp()函数进行有效字符比较的缘故。
写东西时,数组/指针经常换着用,所以有时候也会出现问题(待确认)。
7. 关于多线程的问题。
问题:在服务器端,每个与客户端的通信都有单独的线程,需要删除线程池中的数据;主线程在有链接到来时,需要增加线程池中的数据;轮询线程则继续要读,也需要删除线程池中的数据
这样就至少有三个线程会访问线程池,因此需要用pthread_mutex来锁定,但是单纯用互斥锁又会导致死锁,需要配合条件变量pthread_cond_t来实现线程的等待和唤醒,以实现线程间的同步。
8. 套接字传送String的问题
问题:
string相当于是一个char *,网络传输指针一般都会有问题(除非本机器的线程通信)。
在C#中没有指针的概念,以为可以用string传输,但在验证的时候仍然出错
typedef struct _Info { string name; string cipher; string signature; }Info;解决办法:
把内容放在结构体中,而不要把string类型的对象放进结构体。全部用char[]数组进行存放
在C#中,声明数组时一般不指定数组的大小,而是用new关键字来分配,因此需要重写结构体的构造函数
代码如下:
struct Info { public char[] name; public char[] cipher; public char[] signature; public Info() { name = new char[16]; cipher = new char[16]; signature = new char[256]; } public Info(string name, string cipher, string signature) { this.name = new char[16]; this.name=name.ToCharArray(0, 16); this.cipher = new char[16]; this.cipher=cipher.ToCharArray(0, 16); this.signature = new char[256]; this.signature=signature.ToCharArray(0, 16); } }