基于Windows Socket的安全通信(C++实现,附源码)
来源:互联网 发布:苹果版软件商店 编辑:程序博客网 时间:2024/05/22 10:38
原创作品,转载请注明出自xelz's blog
博客地址:http://mingcn.cnblogs.com/
本文地址:http://mingcn.cnblogs.com/archive/2010/11/01/socket_c.html
被标题吸引到的大牛们原谅我吧,我只是菜鸟一只...
言归正传,还是那个课程设计,续昨天的AES加密(http://mingcn.cnblogs.com/archive/2010/10/31/aes_c.html)
今天完成剩下的Socket通信部分(泪奔中...C++小白,MFC那是大白o(╯□╰)o,控件怎么用都不知道)
本来想退而求其次写个Console Application,后来想着最后一次课程设计了,上点心,咬咬牙,开始...
界面(软肋啊,随便搜了点源码,就弄了个Simple Dialog)
图示:红色为控件的ID, 蓝色为映射的变量名
下面要添加Socket通信功能了
先了解一下Socket的相关函数原型
//加载套接字库
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中添加如下代码
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库占用的系统资源
在析构函数冲添加如下代码
WSACleanup();
Socket通信流程
实现安全通信,应采用面向连接的TCP/IP协议来保证连接的可靠性
面向连接的套接字的系统调用时序图
添加成员变量及初始化
//服务器端:
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”按钮注册单击事件处理服务器端初始化及关闭操作
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
);
//另起线程等待客户端连接
}
接收来自客户端的连接请求
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”按钮注册单击事件
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
);
//连接建立,另起线程用于接收信息
}
用于循环接收信息的线程
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”按钮注册单击事件,处理数据的加密发送
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进制输出以便作演示
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"
;
}
贴出的代码都是服务器端的,客户端代码类似,最大区别就是类名不同,不做赘述
运行效果
最后惯例附上源码 Safe_Socket
- 基于Windows Socket的安全通信(C++实现,附源码)
- 基于Windows Socket的安全通信(C++实现,附源码)
- Windows Socket安全通信(附C++源码)
- 基于Windows Socket的安全通信
- Windows下基于socket多线程并发通信的实现
- 基于c++控制台的Socket通信源码
- C++Socket通信总结(附C++实现)
- windows下用c实现Socket通信
- 基于socket通信的,利用MFC实现TCP通信的C/S架构程序
- 浅谈java socket通信,并附源码
- 基于Socket/ServerSocket多线程实现的聊天室[附源代码]
- socket编程 -- 基于TCP协议的C/S通信模型及实现
- socket编程 -- 基于UDP协议的C/S通信模型及实现
- Socket通信总结(附C++实现)
- Socket通信总结(附C++实现)
- Socket通信总结(附C++实现)
- Socket通信总结(附C++实现)
- android网络编程 -- Socket 通信(03) 点对点Android聊天室实现(带服务器) [附源码分析]
- /sys/bus/usb/devices下的文件命名
- Springmvc json加载数据 前端拼接技术
- android在 Activity 之间传递参数
- libevent7
- html与htm的区别
- 基于Windows Socket的安全通信(C++实现,附源码)
- 浏览器缓存机制
- C#实现MD5加密
- LeetCode_OJ【39】Combination Sum
- 'the django book'读书笔记(第1,2章)
- 通过ssh操作IOS亮屏解锁打开app
- AppleScript学习(重要)
- poj--2631--Roads in the North(树的直径 裸模板)
- python的LEGB原则