标签:style blog http color 使用 width
先了解一下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((unsignedchar *)"0123456789abcdef"), listening(false), connected(false){ //Constructor
of Server}//客户端: SOCKET
toServer;//连接至服务器端的套接字 bool connected;//指示连接状态 AES
aes;//加密/解密模块CTestSocketClientDlg::CTestSocketClientDlg(CWnd*
pParent): CDialog(CTestSocketClientDlg::IDD,
pParent), aes((unsignedchar *)"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
基于Windows Socket的安全通信(C++实现,附源码),布布扣,bubuko.com
基于Windows Socket的安全通信(C++实现,附源码)
标签:style blog http color 使用 width
原文地址:http://blog.csdn.net/kaitiren/article/details/37518317