注意:
1.先把SDL检查关了,不然inet_addr这个类型会报错
2.DLL的功能需要借助平台来体现,所以对于初学者建议先建立一个控制台程序来调试,并且辅以较为成熟的工具来调试能达到更好参考的效果,这次我调试的时候是以SocketTool来作为参考的这个网上有资源。
3.我是借鉴这篇博客的,新建一个C++控制台程序,他有现成的代码,利用SocketTool调试,然后再把代码分块封装就ok了
新建一个工程,具体看我另外一篇博客C++的简单动态链接的创建和引用
接下来是头文件内容,建议先学会创建和引用再来尝试做这个,虽然这个也很简单。
#pragma once
#include<string>
class _declspec(dllexport) TSocket
{
public:
bool Client_Connect(std::string strAddr,int nPort,std::string &strError);
bool Client_DisConnect();
bool Client_TSockSend(std::string strWord, std::string& strError);
bool Client_TSockRecv(std::string &strWord,int nTimeout);
};
然后是cpp的内容,只说实现,不谈原理
#include "pch.h"
#include "TSocket.h"
#include "winsock2.h"
#pragma comment(lib, "ws2_32.lib")
BOOL RecvLine(SOCKET s, char* buf); //Read the data of a line
const int BUF_SIZE = 64;
WSADATA wsd; //WSADATA Variable
SOCKET sHost; //Server socket
SOCKADDR_IN servAddr; //Server Address
char buf[BUF_SIZE]; //Receiving data buffer area
char bufRecv[BUF_SIZE];
int retVal; //return value
bool TSocket::Client_Connect(std::string strAddr, int nPort, std::string& strError)
{
if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
{
strError = "WSAStartup failed!";
return false;
}
//Create socket
sHost = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == sHost)
{
strError = "socket failed!";
WSACleanup();//Release socket resource
return false;
}
//Set server address
servAddr.sin_family = AF_INET;
const char* cAdd = strAddr.c_str();
servAddr.sin_addr.s_addr = inet_addr(cAdd);
servAddr.sin_port = htons((short)nPort);
int nServAddlen = sizeof(servAddr);
//Connect Server
retVal = connect(sHost, (LPSOCKADDR)&servAddr, sizeof(servAddr));
if (SOCKET_ERROR == retVal)
{
strError = "connect failed!";
closesocket(sHost); //close socket
WSACleanup(); //Release socket resource
return false;
}
return true;
}
bool TSocket::Client_DisConnect()
{
closesocket(sHost);
WSACleanup();
return true;
}
bool TSocket::Client_TSockSend(std::string strWord, std::string& strError)
{
//Sending data to the Server
ZeroMemory(buf, BUF_SIZE);
strcpy(buf,strWord.c_str());
retVal = send(sHost, buf, strlen(buf), 0);
if (SOCKET_ERROR == retVal)
{
//cout << "send failed!" << endl;
strError = "send failed!";
closesocket(sHost);
WSACleanup();
return false;
}
return true;
}
bool TSocket::Client_TSockRecv(std::string& strWord,int nTimeout)//0:永远等待
{
bool bRes;
ZeroMemory(bufRecv, BUF_SIZE);
bRes=recv(sHost, bufRecv, BUF_SIZE, 0); // Accepting data from Server,only receiving 5 characters
strWord = bufRecv;
return bRes;
}
编译后即可食用。
给你们看一下我在MFC平台上使用的效果
不知道这样描述准不准确:
因为“接收”函数会阻塞,因此要实现全双工异步这种聊天效果,我选择了使用线程,以下代码是再MFC工程里的。
//这是线程函数
UINT SockRecvThread(LPVOID pParam)
{
while (true)
{
std::string str1;
CString CstrWord;
if (g_pMainThis->m_GlobalSysDefine.m_pTSocket->TSockRecv(str1, 0))
{
CstrWord = str1.c_str();
g_pMainThis->m_pDlgTCPClient->strText += (_T("Recv: ") + CstrWord + _T("\r\n"));
g_pMainThis->m_pDlgTCPClient->m_RecvEdt.SetWindowTextW(g_pMainThis->m_pDlgTCPClient->strText);
}
else
{
g_pMainThis->m_pDlgTCPClient->strText += _T("System: The Server disconnects acttively!");
g_pMainThis->m_pDlgTCPClient->m_RecvEdt.SetWindowTextW(g_pMainThis->m_pDlgTCPClient->strText);
return 0;
}
}
return 0;
}
//这是连接按钮
void DlgTCPClient::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
CString strAddr,strError;
int nPort;
GetDlgItemText(IDC_EDIT1, strAddr);
nPort=GetDlgItemInt(IDC_EDIT2);
std::string str1, str3;
str1 = CW2A(strAddr.GetString());
if (!g_pMainThis->m_GlobalSysDefine.m_pTSocket->Connect(str1,nPort,str3))
{
strError = str3.c_str();
strText += (_T("System: ")+strError+_T("\r\n"));
}
else
{
m_pThread=::AfxBeginThread(SockRecvThread,NULL);//连接成功后启动线程
strText += _T("System: Connect Succesful!\r\n");
}
m_RecvEdt.SetWindowTextW(strText);
}
学习笔记,欢迎指正,轻喷(●ˇ∀ˇ●)。。。