基于Windows Socket的安全通信

转载 2012年03月29日 15:46:35

图示:红色为控件的ID, 蓝色为映射的变量名

 

下面要添加Socket通信功能了

先了解一下Socket的相关函数原型

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//加载套接字库
intPASCAL FAR WSAStartup(WORDwVersionRequired, LPWSADATA lpWSAData);
//释放套接字库资源
intPASCAL FAR WSACleanup(void);
//创建套接字
SOCKET PASCAL FAR socket (intaf,inttype,intprotocol);
//关闭套接字
intPASCAL FAR closesocket (SOCKET s);
//绑定一个IP地址和端口
intPASCAL FAR bind (SOCKET s,conststructsockaddr FAR *addr, intnamelen);
//将套接字置为监听状态
intPASCAL FAR listen (SOCKET s,intbacklog);
//接受客户端连接请求,并返回新创建的套接字
SOCKET PASCAL FAR accept (SOCKET s,structsockaddr FAR *addr,intFAR *addrlen);
//尝试将本地套接字连接至服务器
intPASCAL FAR connect (SOCKET s,conststructsockaddr FAR *name, intnamelen);
//发送数据
intPASCAL FAR send (SOCKET s,constcharFAR * buf,intlen,intflags);
//接收数据
intPASCAL FAR recv (SOCKET s,charFAR * buf,intlen,intflags);

 

使用Socket的程序在使用Socket之前必须调用WSAStartup函数来绑定Socket库

在Constructor中添加如下代码

 

1
2
3
4
5
6
7
8
9
interror;
WORDwVersionRequested;
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;//用于监听的套接字和连接至客户端的套接字(只是为了实现通信模型,所以不考虑多客户端)
  boollistening, connected;//指示监听和连接的状态
  AES aes;//加密/解密模块
  
CTestSocketServerDlg::CTestSocketServerDlg(CWnd* pParent):
    CDialog(CTestSocketServerDlg::IDD, pParent), 
    aes((unsignedchar*)"0123456789abcdef"),
    listening(false),
    connected(false)
{
    //Constructor of Server
}
  
//客户端:
  SOCKET toServer;//连接至服务器端的套接字
  boolconnected;//指示连接状态
  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
voidCTestSocketServerDlg::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
    structprotoent *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及端口
    structsockaddr_in saddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(m_port);
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    if(bind(Listener, (structsockaddr *)&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
UINTWait4Client(LPVOIDpParam)
{
    CTestSocketServerDlg * c = (CTestSocketServerDlg *) pParam;
    structsockaddr_in caddr;
    intcaddrlen =sizeof(caddr);
    c->toClient = accept(c->Listener, (structsockaddr *)&caddr, &caddrlen);
  
    if(c->toClient == INVALID_SOCKET)//异常处理
    {
        if(!c->listening)return0;//服务器端主动关闭,则直接退出
        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);
    }
    return0;
}

 

客户端只需要创建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
voidCTestSocketClientDlg::OnBtnConnect() 
{
    if(connected)//如果已连接,则断开
    {
        connected =false;
        closesocket(toServer);
        m_chat +="Disconnect to Server!\r\n";
        UpdateData(false);
        return;
    }
  
    UpdateData(true);
    //创建Socket
    structprotoent *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;
    }
    //尝试连接服务器
    structsockaddr_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, (structsockaddr *)&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
UINTReceiveMessage(LPVOIDpParam)
{
    CTestSocketServerDlg * c = (CTestSocketServerDlg *) pParam;
    charbuffer[1024];
    interror;//记录recv函数返回值,即接收的字节数,也作异常代码
    while(error = recv(c->toClient, buffer, 1024, 0))
    {
        if(error == 0 || error == SOCKET_ERROR)break;
        c->PrintData("Received Data", (unsignedchar*)buffer, error);
        c->aes.InvCipher((void*)buffer, error);//解密,恢复明文
        c->PrintData("Unencrypted Data", (unsignedchar*)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)return0;//服务器端主动关闭,直接返回
    closesocket(c->toClient);
    c->connected =false;
    c->m_chat +="Client Disconnected...\r\n";
    c->UpdateData(false);
    AfxBeginThread(Wait4Client, c);
    return0;
}

 

为“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
voidCTestSocketServerDlg::OnBtnSend() 
{
    if(!connected)return;
    UpdateData(true);
    if(m_message =="")return;
      
    intlen = m_message.GetLength()+1 >= 1024 ? 1024 : m_message.GetLength()+1;
    len = len%16 ? len+16-len%16 : len;
    charbuffer[1024];
    strcpy(buffer,m_message.GetBuffer(0));//将message拷贝至buffer数组中
    m_message.ReleaseBuffer();
    PrintData("Input Data", (unsignedchar*)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", (unsignedchar*)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
voidCTestSocketServerDlg::PrintData(char* title, unsignedchar* buffer,intlength)
{
    inti;
    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";
}

 

贴出的代码都是服务器端的,客户端代码类似,最大区别就是类名不同,不做赘述

 

运行效果

相关文章推荐

基于Windows Socket的安全通信(C++实现,附源码)

先了解一下Socket的相关函数原型   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...

flex与socket通信之成功----之成功补充篇(关于C#建立FLASH服务端的安全沙箱问题)

注意:XMLSocket 接收到服务端下发的数据时,将连续放于接收缓冲区,直到接收到 "\0" 字节(字节内容为 ASCII 值 0),才认为接收完成,并调用相应的 onData 或 onXML ...

[教程] Flash Socket通信的安全策略问题 843端口

1、问题描述       将flash发布为html格式后,加载页面后,swf无法与服务器进行socket通信。Flash端显示的错误为: securityErrorHandler信息: [S...
  • wclin88
  • wclin88
  • 2012年02月24日 17:41
  • 1442

浅谈Flash Socket通信安全沙箱

用过Flash socket的同学都知道,Flash socket通讯有安全沙箱问题。就是在Flash Player发起socket通信时,会向服务端获取安全策略,如果得不到服务端响应,flash将无...
  • cwqcwk1
  • cwqcwk1
  • 2014年04月29日 23:18
  • 2698

Flash Socket通信的安全策略

昨天做测试的时候遇到一个问题,做好的SWF在Flash AS3中调试通过,但是发布到html中之后就无法得到数据了。查了一些资料之后找到了解决办法。这里感谢 剑心 提供帮助,以及同事若水三千提供Jav...

windows socket通信程序

  • 2009年05月21日 20:51
  • 44KB
  • 下载

Windows下的Socket通信

  • 2016年03月22日 15:06
  • 14.65MB
  • 下载

windows phone 7 与wifi小车的socket通信

wp7手机要对wifi小车发送控制指令,在建立好wifi连接之后,就要用socket通信了。之前介绍了703n路由里ser2net包的强大功能(能将ttl串口信号和net信号相互转换),下位机仍然只管...
  • cooska
  • cooska
  • 2012年12月13日 10:12
  • 2675
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于Windows Socket的安全通信
举报原因:
原因补充:

(最多只允许输入30个字)