📄 tcpclientexdlg.cpp
字号:
// TCPClientExDlg.cpp : implementation file
//
#include "stdafx.h"
#include "TCPClientEx.h"
#include "TCPClientExDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTCPClientExDlg dialog
CTCPClientExDlg::CTCPClientExDlg(CWnd* pParent /*=NULL*/)
: CDialog(CTCPClientExDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CTCPClientExDlg)
m_RemoteHost = _T("");
m_RemotePort = 0;
m_SendEdit = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CTCPClientExDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTCPClientExDlg)
DDX_Control(pDX, IDC_CREATE_CONNECT, m_ButCreConnect);
DDX_Control(pDX, IDC_DISCONNECT, m_ButDisConnect);
DDX_Text(pDX, IDC_REMOTEHOST, m_RemoteHost);
DDX_Text(pDX, IDC_REMOTEPORT, m_RemotePort);
DDX_Text(pDX, IDC_SEND_EDIT, m_SendEdit);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CTCPClientExDlg, CDialog)
//{{AFX_MSG_MAP(CTCPClientExDlg)
ON_WM_DESTROY()
ON_BN_CLICKED(IDC_CREATE_CONNECT, OnCreateConnect)
ON_BN_CLICKED(IDC_CLEAR_RECDISP, OnClearRecdisp)
ON_BN_CLICKED(IDC_SEND, OnSend)
ON_BN_CLICKED(IDC_DISCONNECT, OnDisconnect)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTCPClientExDlg message handlers
BOOL CTCPClientExDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
CenterWindow(GetDesktopWindow()); // center to the hpc screen
m_RemoteHost = "192.168.0.16"; /* 默认远程主机 IP 地址 */
m_RemotePort = 1011; /* 默认远程主机端口 */
m_strRecDisp = _T(""); /* 清空接收区字符 */
m_Socket = INVALID_SOCKET; /* Socket 无效 */
m_ExitThreadEvent = NULL; /* TCP 接收线程退出事件无效 */
m_ButDisConnect.EnableWindow(FALSE); /* "断开连接" 按键无效 */
UpdateData(FALSE);
return TRUE;
}
/*******************************************************************************************
函数名称: CALLBACK CTCPClientExDlg::OnTcpRecv
描 述: TCP 接收数据成功回调函数
输入参数: 无
输出参数: 无
返 回: FALSE: 失败; TRUE: 成功
********************************************************************************************/
void CALLBACK CTCPClientExDlg::OnTcpRecv(CWnd* pWnd, char *buf, int buflen)
{
CString strTmp;
CTCPClientExDlg * pDlg = (CTCPClientExDlg*)pWnd;
CEdit *pRecvStrEdit = (CEdit*)pDlg->GetDlgItem(IDC_REC_DISP);
/* 取得控件指针 */
for (int i = 0; i < buflen; i++)
{
strTmp.Format(_T("%c"), *buf);
pDlg->m_strRecDisp += strTmp;
buf++;
}
pRecvStrEdit->SetWindowText(pDlg->m_strRecDisp); /* 在窗口显示出来 */
}
/*******************************************************************************************
函数名称: CALLBACK CTCPClientExDlg::OnTcpError
描 述: TCP 错误回调函数
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CALLBACK CTCPClientExDlg::OnTcpError(CWnd *pWnd, int nErrorCode)
{
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::TCPRecvTread
描 述: TCP 接收线程
输入参数: LPVOID lparam: 线程参数,创建线程时传入
输出参数: 无
返 回: 0: 线程退出, 返回值没特殊含义
********************************************************************************************/
DWORD CTCPClientExDlg::TCPRecvTread(LPVOID lparam)
{
fd_set fdRead;
TIMEVAL aTime;
int iErrorCode;
int ret;
aTime.tv_sec = 1;
aTime.tv_usec = 0;
CTCPClientExDlg *pDlg = (CTCPClientExDlg *)lparam;
while(TRUE)
{
if (WaitForSingleObject(pDlg->m_ExitThreadEvent, 0) == WAIT_OBJECT_0)
break;
FD_ZERO(&fdRead);
FD_SET(pDlg->m_Socket, &fdRead);
ret = select(0, &fdRead, NULL, NULL, &aTime);
if (ret == SOCKET_ERROR)
{
iErrorCode = WSAGetLastError();
pDlg->OnTcpError(pDlg, iErrorCode);
break;
}
if (ret > 0)
{
if (FD_ISSET(pDlg->m_Socket, &fdRead)) /* 检查该socket是否是fdRead中的一员 */
{
char *recvBuf = new char[1024];
// 接收数据
int recvlen = recv(pDlg->m_Socket, recvBuf, 1024, 0);
if ((recvlen == SOCKET_ERROR) || (recvlen == 0))
{
iErrorCode = WSAGetLastError();
pDlg->OnTcpError(pDlg, iErrorCode);
delete[] recvBuf;
break;
}
else
{
pDlg->OnTcpRecv(pDlg, recvBuf, recvlen); /* 正确接收回调函数 */
delete[] recvBuf;
}
}// end of if (FD_ISSET(pDlg->m_Socket, &fdRead))
}// end of if (ret > 0)
}// end of while(TRUE)
return 0;
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::OnCreateConnect
描 述: "创建连接" 按键单击事件代码
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CTCPClientExDlg::OnCreateConnect()
{
WSADATA wsa;
DWORD IDThread;
if (WSAStartup(MAKEWORD(1,1), &wsa) != 0) /* WinSock 初始化 */
{
MessageBox(_T("加载套接字失败!"));
return;
}
m_Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); /* 创建TCP套接字 */
if (m_Socket == INVALID_SOCKET)
{
WSACleanup();
MessageBox(_T("创建套接字失败!"));
return;
}
UpdateData(TRUE);
// 初始化远程 IP 地址及端口
m_RemoteAddr.sin_family = AF_INET;
m_RemoteAddr.sin_port = htons(m_RemotePort); /* 远程端口地址 */
char charRemoteHost[255];
ZeroMemory(charRemoteHost, 255);
int len = m_RemoteHost.GetLength();
if (len > 255)
{
MessageBox(_T("输入远程IP长度超长!"));
return;
}
// 将 Unicode 字符串转换为字节
LPTSTR pStr = m_RemoteHost.GetBuffer(len);
WideCharToMultiByte(CP_ACP, 0, pStr, len, charRemoteHost, len, NULL, NULL);
DWORD ipaddress = inet_addr(charRemoteHost); /* 远程 IP 地址 */
if ((INADDR_NONE == ipaddress) || (0 == ipaddress))
{
MessageBox(_T("输入远程IP地址格式不正确!"));
return;
}
m_RemoteAddr.sin_addr.s_addr = ipaddress;
// 连接远程TCP服务器
int ret = connect(m_Socket, (struct sockaddr *)&m_RemoteAddr, sizeof(m_RemoteAddr));
if (ret == SOCKET_ERROR)
{
MessageBox(_T("连接TCP服务器失败!"));
return;
}
DWORD ul = 1;
ioctlsocket(m_Socket, FIONBIO, &ul); /* 设置通信模式为异步模式 */
m_ExitThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); /* 创建 TCP 接收线程退出事件 */
// 创建 TCP 接收线程
HANDLE hRecvThread = CreateThread(0, 0, TCPRecvTread, this, 0, &IDThread);
if (hRecvThread == NULL)
{
closesocket(m_Socket);
MessageBox(_T("创建TCP接收线程失败!"));
}
CloseHandle(hRecvThread); /* 关闭接收线程句柄 */
m_ButDisConnect.EnableWindow(TRUE);
m_ButCreConnect.EnableWindow(FALSE);
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::OnDisconnect
描 述: "断开连接" 按键单击事件代码, 断开与远程TCP服务器的连接
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CTCPClientExDlg::OnDisconnect()
{
if (m_ExitThreadEvent != NULL)
{
SetEvent(m_ExitThreadEvent); /* 设置接收线程退出事件, 通知线程退出 */
Sleep(1000);
CloseHandle(m_ExitThreadEvent); /* 关闭线程退出事件句柄 */
}
if (m_Socket != INVALID_SOCKET)
{
if (closesocket(m_Socket) == SOCKET_ERROR) /* 关闭 Socket */
{
MessageBox(_T("关闭Socket失败!"));
return;
}
m_Socket = INVALID_SOCKET;
if (WSACleanup() == SOCKET_ERROR) /* 释放Socket资源*/
MessageBox(_T("释放Socket资源失败!"));
}
m_ButDisConnect.EnableWindow(FALSE); /* 禁止"断开连接"按键 */
m_ButCreConnect.EnableWindow(TRUE); /* 使能"创建连接"按键 */
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::OnSend
描 述: "发送" 按键单击事件代码
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CTCPClientExDlg::OnSend()
{
int nErrorCode;
int cnt = 0, actlen = 0;
if (m_Socket == NULL)
return;
UpdateData(TRUE);
int sendlen = m_SendEdit.GetLength(); /* 取得输入字符串长度 */
char *psendbuff = new char[sendlen];
for(int i = 0; i < sendlen;i++)
psendbuff[i] = (char)m_SendEdit.GetAt(i); /* 转换为单字节字符 */
while(cnt < sendlen)
{ // 发送数据
actlen = send(m_Socket, psendbuff + cnt, sendlen - cnt, 0);
if (actlen == SOCKET_ERROR )
{
MessageBox(_T("TCP 数据发送失败!"));
nErrorCode = WSAGetLastError();
delete[] psendbuff;
return;
}
cnt = cnt + actlen;
if (cnt < sendlen)
Sleep(1000);
}
delete[] psendbuff;
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::OnClearRecdisp
描 述: "清除接收区" 按键单击事件代码
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CTCPClientExDlg::OnClearRecdisp()
{
m_strRecDisp = _T("");
CEdit *pRecDispEdit = (CEdit*)GetDlgItem(IDC_REC_DISP); /* 取得控件指针 */
pRecDispEdit->SetWindowText(m_strRecDisp); /* 在窗口显示出来 */
}
/*******************************************************************************************
函数名称: CTCPClientExDlg::OnDestroy
描 述: 对话框关闭事件处理函数
输入参数: 无
输出参数: 无
返 回: 无
********************************************************************************************/
void CTCPClientExDlg::OnDestroy()
{
CDialog::OnDestroy();
OnDisconnect(); /* 断开连接 */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -