利用winsock api函数编写tcp client的过程如下
1、加载winsock #define WINSOCK_VERSION MAKEWORD(2,2)
WORD wVersionRequested; //定义socket1.1或者socket2.0
wVersionRequested = MAKEWORD(2, 2); //定义连接为socket2.0
//装载socket2.0支持
int Ret=WSAStartup(wVersionRequested, &wsaData);
if (Ret != 0)
{
printf("WSAStartup failed with error %d\n", Ret);
return;
}
2、创建套接字tcp
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
{
printf("socket failed with error %d\n", WSAGetLastError());
WSACleanup();
return;
}
3、设置地址结构体
char cIP[20];
memset(cIP, 0, sizeof(cIP));
int nLen = ip.GetLength();
for(int i=0; i<nLen; i++)
cIP[i] =(char)ip.GetAt(i);
//设置地址结构体
ServerAddr.sin_family = AF_INET;
ServerAddr.sin_port = htons(m_port);
ServerAddr.sin_addr.s_addr = inet_addr(cIP);
4、创建连接
if (connect(sock, (SOCKADDR *) &ServerAddr, sizeof(ServerAddr))
== SOCKET_ERROR)
{
printf("connect failed with error %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return;
}
5、创建线程或者消息映射
//选择方式
CButton *pck = (CButton*)GetDlgItem(IDC_CK_THREAD);
if(pck->GetCheck())
{
hThread=CreateThread(NULL, 0, CommRecvTread, this, 0, NULL);
if(hThread == INVALID_HANDLE_VALUE)
{
AfxMessageBox(CString("不能创建socket事件监听线程!"));
return;
}
CloseHandle(hThread);
}
else
{
if(SOCKET_ERROR==WSAAsyncSelect(sock,m_hWnd,UM_SOCK,FD_READ))
{
MessageBox(L"注册网络读取事件失败!");
return;
}
}
对于线程的说明
//线程相关声明
HANDLE hThread;
static DWORD WINAPI CommRecvTread(LPVOID lpParameter);
typedef void (CALLBACK *ONCOMMRECV)(CWnd* pWnd, char *buf, int buflen);
static void CALLBACK OnCommRecv(CWnd* pWnd, char *buf, int buflen);
DWORD WINAPI CSocket_TCP_ClientDlg::CommRecvTread(LPVOID lparam)
{
DWORD dwLength;
char *recvBuf = new char[1024];
ZeroMemory(recvBuf, 1024); //指定内存清零
CSocket_TCP_ClientDlg *pDlg = (CSocket_TCP_ClientDlg*)lparam;
while(TRUE)
{
int Ret = recv(pDlg->sock, recvBuf, 1024, 0);
OnCommRecv(pDlg, recvBuf, Ret);
}
return 0;
}
void CALLBACK CSocket_TCP_ClientDlg::OnCommRecv(CWnd* pWnd, char *buf, int buflen)
{
CString tmp = L"";
CSocket_TCP_ClientDlg * pDlg = (CSocket_TCP_ClientDlg*)pWnd;
CEdit *pRecvStrEdit = (CEdit*)pDlg->GetDlgItem(IDC_EDT_REV);
CButton *pck = (CButton*)pDlg->GetDlgItem(IDC_CHECK_HexRev);
pDlg->m_strRecDisp=L"";
/* 取得控件指针 */
if(pck->GetCheck())
{
for (int i = 0; i < buflen; i++)
{
tmp.Format(_T("%X"), (byte)buf[i]); /* 无符号整型 */
pDlg->m_strRecDisp += tmp;
}
}
else
{
for (int i = 0; i < buflen; i++, buf++)
{
tmp.Format(_T("%c"), *buf); /* 将字符转换为字符串 */
pDlg->m_strRecDisp += tmp;
}
}
//pDlg->m_strRecDisp += GetCurrentDateTime() + L"\r\n";
pRecvStrEdit->SetWindowText(pDlg->m_strRecDisp); /* 显示在窗口上 */
}
对于消息映射的说明,比较常用
const int UM_SOCK = WM_USER + 1;//自定义消息
afx_msg LRESULT OnSock(WPARAM, LPARAM); //消息原型声明
//消息映射
ON_MESSAGE(UM_SOCK, OnSock) //非常重要;在BEGIN_MESSAGE_MAP(CSocket_TCP_ClientDlg, CDialog)里面
LRESULT CSocket_TCP_ClientDlg::OnSock(WPARAM wParam, LPARAM lParam)
{
switch(LOWORD(lParam))
{
case FD_READ:
char *recvBuf = new char[1024];
ZeroMemory(recvBuf, 1024); //指定内存清零
int Ret = recv(sock, recvBuf, 1024, 0);
CString tmp=L"";
CEdit *pRecvStrEdit = (CEdit*)GetDlgItem(IDC_EDT_REV);
CButton *pck = (CButton*)GetDlgItem(IDC_CHECK_HexRev);
m_strRecDisp=L"";
/* 取得控件指针 */
if(pck->GetCheck())
{
for (int i = 0; i < Ret; i++)
{
tmp.Format(_T("%X"), (byte)recvBuf[i]); /* 无符号整型 */
m_strRecDisp += tmp;
}
}
else
{
/*
for (int i = 0; i < Ret; i++, recvBuf++)
{
tmp.Format(_T("%c"), *recvBuf); // 将字符转换为字符串
m_strRecDisp += tmp;
}
*/
m_strRecDisp = CString(recvBuf);
}
//pDlg->m_strRecDisp += GetCurrentDateTime() + L"\r\n";
pRecvStrEdit->SetWindowText(m_strRecDisp); /* 显示在窗口上 */
break;
}
return 1L;
}
对于CE的程序,一般使用线程方式来接收,关闭窗口的时候取消线程的方式
void CSocket_TCP_ClientDlg::OnDestroy()
{
CDialog::OnDestroy();
// TODO: 在此处添加消息处理程序代码
if (hThread != INVALID_HANDLE_VALUE)
{
TerminateThread(hThread,0);
CloseHandle(hThread);
hThread = INVALID_HANDLE_VALUE;
}
}