首页 > 代码库 > 基于Windows Socket的安全通信(C++实现,附源码)
基于Windows Socket的安全通信(C++实现,附源码)
先了解一下Socket的相关函数原型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //加载套接字库 int PASCAL FAR WSAStartup( WORD wVersionRequired, LPWSADATA lpWSAData); //释放套接字库资源 int PASCAL FAR WSACleanup( void ); //创建套接字 SOCKET PASCAL FAR socket ( int af, int type, int protocol); //关闭套接字 int PASCAL FAR closesocket (SOCKET s); //绑定一个IP地址和端口 int PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen); //将套接字置为监听状态 int PASCAL FAR listen (SOCKET s, int backlog); //接受客户端连接请求,并返回新创建的套接字 SOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); //尝试将本地套接字连接至服务器 int PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen); //发送数据 int PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags); //接收数据 int PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags); |
使用Socket的程序在使用Socket之前必须调用WSAStartup函数来绑定Socket库
在Constructor中添加如下代码
1 2 3 4 5 6 7 8 9 | int error; WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 1); //加载2.1版本的Socket库 if (error = WSAStartup(wVersionRequested, &wsaData)) { AfxMessageBox( "Link Socket Library Failed!" ); exit (0); } |
应用程序完成对Socket的使用后应当调用WSACleanup函数来释放Socket库占用的系统资源
在析构函数冲添加如下代码
1 | WSACleanup(); |
Socket通信流程
实现安全通信,应采用面向连接的TCP/IP协议来保证连接的可靠性
面向连接的套接字的系统调用时序图
添加成员变量及初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | //服务器端: SOCKET Listener,toClient; //用于监听的套接字和连接至客户端的套接字(只是为了实现通信模型,所以不考虑多客户端) bool listening, connected; //指示监听和连接的状态 AES aes; //加密/解密模块 CTestSocketServerDlg::CTestSocketServerDlg(CWnd* pParent): CDialog(CTestSocketServerDlg::IDD, pParent), aes((unsigned char *) "0123456789abcdef" ), listening( false ), connected( false ) { //Constructor of Server } //客户端: SOCKET toServer; //连接至服务器端的套接字 bool connected; //指示连接状态 AES aes; //加密/解密模块 CTestSocketClientDlg::CTestSocketClientDlg(CWnd* pParent): CDialog(CTestSocketClientDlg::IDD, pParent), aes((unsigned char *) "0123456789abcdef" ), connected( false ) { //Constructor of Client } |
为“Start/Stop”按钮注册单击事件处理服务器端初始化及关闭操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | void CTestSocketServerDlg::OnBtnStart() { if (connected || listening) //若正在监听或已连接则关闭服务器 { connected = false ; listening = false ; closesocket(toClient); closesocket(Listener); m_chat += "Socket Server Stopped!\r\n" ; UpdateData( false ); return ; } UpdateData( true ); //创建监听Socket struct protoent *ppe; ppe = getprotobyname( "tcp" ); if ((Listener = socket(PF_INET, SOCK_STREAM, ppe->p_proto)) == INVALID_SOCKET) { m_chat += "Initialize Socket Listener Failed!\r\n" ; UpdateData( false ); return ; } //绑定IP及端口 struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(m_port); saddr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(Listener, ( struct sockaddr *)&saddr, sizeof (saddr))) { m_chat += "Bind to IPEndPoint Failed! (Port in use?)\r\n" ; UpdateData( false ); return ; } //开始监听,队列长度1(不考虑多客户端) if (listen(Listener, 1)) { m_chat += "Listen Failed!\r\n" ; UpdateData( false ); return ; } m_chat += "Socket Server Started!\r\n" ; UpdateData( false ); listening = true ; AfxBeginThread(Wait4Client, this ); //另起线程等待客户端连接 } |
接收来自客户端的连接请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | UINT Wait4Client( LPVOID pParam) { CTestSocketServerDlg * c = (CTestSocketServerDlg *) pParam; struct sockaddr_in caddr; int caddrlen = sizeof (caddr); c->toClient = accept(c->Listener, ( struct sockaddr *)&caddr, &caddrlen); if (c->toClient == INVALID_SOCKET) //异常处理 { if (!c->listening) return 0; //服务器端主动关闭,则直接退出 c->m_chat += "Connect Failed!\r\n" ; c->UpdateData( false ); return -1; } else { c->connected = true ; //连接建立,另起线程用于接收信息 AfxBeginThread(ReceiveMessage, c); c->m_chat += "Client: " ; c->m_chat += inet_ntoa(caddr.sin_addr); c->m_chat += " Connected!\r\n" ; c->m_ip = inet_ntoa(caddr.sin_addr); c->UpdateData( false ); } return 0; } |
客户端只需要创建Socket并尝试与服务器连接
为“Connect/Disconnect”按钮注册单击事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | void CTestSocketClientDlg::OnBtnConnect() { if (connected) //如果已连接,则断开 { connected = false ; closesocket(toServer); m_chat += "Disconnect to Server!\r\n" ; UpdateData( false ); return ; } UpdateData( true ); //创建Socket struct protoent *ppe; ppe = getprotobyname( "tcp" ); if ((toServer = socket(PF_INET, SOCK_STREAM, ppe->p_proto)) == INVALID_SOCKET) { m_chat += "Initialize Socket Listener Failed!\r\n" ; UpdateData( false ); return ; } //尝试连接服务器 struct sockaddr_in saddr; saddr.sin_family = AF_INET; saddr.sin_port = htons(m_port); saddr.sin_addr.s_addr = inet_addr(m_ip); if (connect(toServer, ( struct sockaddr *)&saddr, sizeof (saddr))) { m_chat += "Connect Failed!\r\n" ; UpdateData( false ); return ; } m_chat += "Server: " ; m_chat += inet_ntoa(saddr.sin_addr); m_chat += " Connected!\r\n" ; connected = true ; UpdateData( false ); AfxBeginThread(ReceiveMessage, this ); //连接建立,另起线程用于接收信息 } |
用于循环接收信息的线程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | UINT ReceiveMessage( LPVOID pParam) { CTestSocketServerDlg * c = (CTestSocketServerDlg *) pParam; char buffer[1024]; int error; //记录recv函数返回值,即接收的字节数,也作异常代码 while (error = recv(c->toClient, buffer, 1024, 0)) { if (error == 0 || error == SOCKET_ERROR) break ; c->PrintData( "Received Data" , (unsigned char *)buffer, error); c->aes.InvCipher(( void *)buffer, error); //解密,恢复明文 c->PrintData( "Unencrypted Data" , (unsigned char *)buffer, error); c->m_chat += "Client:" ; c->m_chat += buffer; c->m_chat += "\r\n" ; c->UpdateData( false ); } c->m_ip = "Not Connected..." ; c->UpdateData( false ); if (!c->connected) return 0; //服务器端主动关闭,直接返回 closesocket(c->toClient); c->connected = false ; c->m_chat += "Client Disconnected...\r\n" ; c->UpdateData( false ); AfxBeginThread(Wait4Client, c); return 0; } |
为“Send”按钮注册单击事件,处理数据的加密发送
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void CTestSocketServerDlg::OnBtnSend() { if (!connected) return ; UpdateData( true ); if (m_message == "" ) return ; int len = m_message.GetLength()+1 >= 1024 ? 1024 : m_message.GetLength()+1; len = len%16 ? len+16-len%16 : len; char buffer[1024]; strcpy (buffer,m_message.GetBuffer(0)); //将message拷贝至buffer数组中 m_message.ReleaseBuffer(); PrintData( "Input Data" , (unsigned char *)buffer, len); aes.Cipher(( void *)buffer); //对数据进行加密 if (send(toClient, buffer, len, 0) == SOCKET_ERROR) //发送密文 { m_chat += "Send Failed!(Socket Exception?)\r\n" ; UpdateData( false ); return ; } PrintData( "Encrypted Data" , (unsigned char *)buffer, len); m_chat += "Server:" + m_message + "\r\n" ; m_message = "" ; UpdateData( false ); } |
发送和接收的时候都用到了一个函数PrintData,用于将明文或密文以16进制输出以便作演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | void CTestSocketServerDlg::PrintData( char * title, unsigned char * buffer, int length) { int i; CString temp( "" ); m_chat += "(" ; m_chat += title; m_chat += ":" ; for (i=0; i<length; i++) { temp.Format( "%s%X " ,*(buffer+i)>15? "" : "0" ,*(buffer+i)); m_chat += temp; } m_chat += ")\r\n" ; } |
代码地址:http://download.csdn.net/detail/kaitiren/7604097
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。