今天我们就来用C++来编写一个简单的聊天小程序,同时是想让大家了解一下C/S架构,看看服务器和客户端是怎样的一个通信流程。对于那些想编写远程控制的小伙伴,这些通信流程你必须要清楚。想实现服务器和客户端的通信,我们就必须要用到Socket(套接字)接口。Socket网络通信涉及到的俩种协议 一种是 TCP协议、还有一种就是UDP协议。俩种协议各有各的优点,不同的环境可以采用不用的协议。
本文章转载至《黑客技术流》
接下来我们用到的通信协议是TCP协议,相比较用TCP协议进行通信 会比用UDP协议更加麻烦一些。TCP协议通信不仅需要编写一个服务端,而且还需要编写一个客户端。
image看着上面的图步骤还挺多的,用到的都是系统自带的Api函数。如果你没有Api编程开发基础,看到这里你已经很厉害了。建议你先去百度学习一下上面的几个Api函数在来看这篇文章,不然在接着看下去看不懂,自信心会很受打击的。服务端代码
<pre class="wp-block-preformatted">#include "stdafx.h"
include <Windows.h>
pragma comment(lib,"Ws2_32.lib")
SOCKET Srever, Client; //创建服务端 客户端套接字
bool Socket_Init(char *IP, int Port);//初始化
UINT Receive_Data(LPVOID lpVoid);//接收数据
void SendMsg(char *pszSend);//发送数据
int _tmain(int argc, _TCHAR* argv[])
{
if (0 == Socket_Init("127.0.0.1",7075))
{
printf("初始化监听端口失败!\n");
return 0;
}
printf("监听端口成功等待客户端连接!\n");
char SendData[MAX_PATH] = { 0 };
while (TRUE)
{
gets(SendData);
SendMsg(SendData);
}
return 0;
}
bool Socket_Init(char *IP, int Port)
{
//初始化Winsock库
WSADATA Data = { 0 };
::WSAStartup(MAKEWORD(2, 2), &Data);//2.2版本
//第一步创建socket
Srever = socket(AF_INET, SOCK_STREAM, 0);
if (Srever == INVALID_SOCKET) return 0;//创建失败就返回
//第二部 绑定端口
sockaddr_in addr;//创建结构体
addr.sin_family = AF_INET;//通信协议
addr.sin_addr.S_un.S_addr = ::inet_addr(IP);//IP
addr.sin_port = ::htons(Port);//端口
if (::bind(Srever, (sockaddr*)&addr, sizeof(addr)) != 0)return 0;//失败返回
//第三部 监听端口
if (listen(Srever, 5) != 0)return 0;//失败返回
//创建线程
CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Receive_Data,NULL, NULL, NULL);
}
UINT Receive_Data(LPVOID lpVoid)
{
//第四部 接受客户连接请求
sockaddr_in addr = { 0 };//创建结构体 用于获取客户IP
int len = sizeof(addr);
Client = accept(Srever, (sockaddr*)&addr, &len);//接受客户端的连接
//第五步 接受数据
char StrBuf[MAX_PATH] = { 0 };//数据缓冲区
while (true)
{
//
if (recv(Client,StrBuf,MAX_PATH,0)<= 0) continue;
printf("[她]%s\n", StrBuf);
}
return 0;
}
//第六步 发送数据
void SendMsg(char *pszSend)
{
// 发送数据
::send(Client, pszSend, (1 + ::lstrlen(pszSend)), 0);
printf("[我]%s\n", pszSend);
}</pre>
客户端代码
<pre class="wp-block-preformatted">#include "stdafx.h"
include <Winsock2.h>
pragma comment(lib, "Ws2_32.lib")
SOCKET Client;// 客户端套接字
//连接服务端
BOOL Connection(char *lpszServerIp, int iServerPort);
void SendMsg(char *pszSend);// 发送数据
UINT Receive_Data(LPVOID lpVoid);//多线程接收数据
int _tmain(int argc, _TCHAR* argv[])
{
// 连接到服务器
if (FALSE == Connection("127.0.0.1", 7075))
{
printf("Connection Error.\n");
}
printf("Connection OK.\n");
// 发送信息
char szSendBuf[MAX_PATH] = { 0 };
while (TRUE)
{
gets(szSendBuf);
// 发送数据
SendMsg(szSendBuf);
}
return 0;
}
BOOL Connection(char *lpszServerIp, int iServerPort)
{
// 初始化 Winsock 库
WSADATA wsaData = { 0 };
::WSAStartup(MAKEWORD(2, 2), &wsaData);
// 创建流式套接字
Client = ::socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == Client)
{
return FALSE;
}
// 设置服务端地址和端口信息
sockaddr_in addr = { 0 };
addr.sin_family = AF_INET;
addr.sin_port = ::htons(iServerPort);
addr.sin_addr.S_un.S_addr = ::inet_addr(lpszServerIp);
// 连接到服务器
if (0 != ::connect(Client, (sockaddr *)(&addr), sizeof(addr)))
{
return FALSE;
}
// 创建接收数据多线程
::CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)Receive_Data, NULL, NULL, NULL);
return TRUE;
}
// 发送数据
void SendMsg(char *pszSend)
{
// 发送数据
::send(Client, pszSend, (1 + ::lstrlen(pszSend)), 0);
printf("[我]%s\n", pszSend);
}
// 接收数据多线程
UINT Receive_Data(LPVOID lpVoid)
{
char szBuf[MAX_PATH] = { 0 };
while (TRUE)
{
// 接收数据
int iRet = ::recv(Client, szBuf, MAX_PATH, 0);
if (0 >= iRet)
{
continue;
}
printf("[她]%s\n", szBuf);
}
return 0;
}</pre>
通过上面一系列的代码,就可以实现服务端与客户端的通信了,因为为了写文章方便,我把所有的代码都集成到了一个CPP文件中。这样会显得不是很简洁,你们可以自行随意改动这些代码。
image从上图可以看到,这样就完成了一次简单的通信了。因为用的是win32控制台程序编写的,所有看上去可能不是很理想。如果说是用MFC界面编写的话,估计我这篇文章写一下午都写不好。
网友评论