头文件
afxsock.h
AfxSocketInit() 函数必须在使用socket之前实现
继承关系
class CSocket : public CAsyncSocket
class CAsyncSocket : public CObject
客户端
- 构造一个CSocket对象。
- 使用该对象调用Create函数创建底层SOCKET句柄,因为客户端不需要绑定任何端口和地址, 所以用默认参数即可
- 调用Connect函数将套接字对象连接到服务器套接字,指定服务器地址和端口号
流程:
socket()
create()
connect()
receive() / send()
close()
代码实现:
// 初始化
AfxSocketInit();
// 创建 CSocket 对象
CSocket aSocket;
// 初始化 CSocket 对象, 因为客户端不需要绑定任何端口和地址, 所以用默认参数即可
if ( ! aSocket.Create())
{
char szMsg[1024] = {0};
sprintf(szMsg, "create faild: %d", aSocket.GetLastError());
AfxMessageBox(szMsg);
return;
}
// 连接指定的地址和端口
if (aSocket.Connect(strIP, nPort))
{
char szRecValue[1024] = {0};
//发送内容给服务器
aSocket.Send(strText, strText.GetLength());
//接收服务器发送回来的内容(该方法会阻塞, 在此等待有内容接收到才继续向下执行)
aSocket.Receive((void *)szRecValue, 1024);
AfxMessageBox(szRecValue);
}
else
{
char szMsg[1024] = {0};
sprintf(szMsg, "create faild: %d", aSocket.GetLastError());
AfxMessageBox(szMsg);
}
// 关闭
aSocket.Close();
服务端
- 构造一个CSocket对象。
- 使用该对象调用Create函数创建底层SOCKET句柄,在Create调用中指定端口(不需要再调用bind函数,因为create中已经调用bind),或者直接使用bind函数,指定端口
- 调用Listen开始监听来自客户端的连接尝试。收到连接请求后,通过调用Accept接受它。
流程:
socket()
bind() or create()
listen()
accept()
receive() / send()
close()
注意:
使用Create创建,因为容易会出现10048错误
解决方案:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
//设置Socket的选项, 解决10048错误必须的步骤
aSocket.SetSockOpt(SO_REUSEADDR, ( void * ) & bOptVal, bOptLen, SOL_SOCKET);
代码实现:
//初始化Winscok
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
return 1;
}
//socket------------------------------------------------
CSocket aSocket, serverSocket;
//调用Socket函数,最好不要使用aSocket.Create创建,因为容易会出现10048错误
if (!aSocket.Socket())
{
char szError[256] = {0};
sprintf(szError, "Create Faild: %d", GetLastError());
AfxMessageBox(szError);
return 1;
}
//绑定端口
if (!aSocket.Bind(nPort))
{
char szError[256] = {0};
sprintf(szError, "Bind Faild: %d", GetLastError());
AfxMessageBox(szError);
return 1;
}
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
//设置Socket的选项, 解决10048错误必须的步骤
aSocket.SetSockOpt(SO_REUSEADDR, ( void * ) & bOptVal, bOptLen, SOL_SOCKET);
//监听
if ( ! aSocket.Listen( 10 ))
{
char szError[256] = {0};
sprintf(szError, "Listen Faild: %d", GetLastError());
AfxMessageBox(szError);
return 1;
}
//接收外部连接
if(!aSocket.Accept(serverSocket))
{
return 1;
}
char szRecvMsg[256] = {0};
//接收客户端内容:阻塞
serverSocket.Receive(szRecvMsg, 256);
//发送内容给客户端
serverSocket.Send("Have Receive The Msg", 50);
//关闭
aSocket.Close();
serverSocket.Close();
CSocket类定义
// CSocket头文件定义
class CSocket : public CAsyncSocket
{
DECLARE_DYNAMIC(CSocket);
private:
CSocket(const CSocket& rSrc); // 没有实现
void operator=(const CSocket& rSrc); // 没有实现
// 构造
public:
CSocket();
BOOL Create(UINT nSocketPort = 0, int nSocketType=SOCK_STREAM,
LPCTSTR lpszSocketAddress = NULL);
// Attributes
public:
BOOL IsBlocking();
static CSocket* PASCAL FromHandle(SOCKET hSocket);
BOOL Attach(SOCKET hSocket);
// Operations
public:
void CancelBlockingCall();
// Overridable callbacks
protected:
virtual BOOL OnMessagePending();
// Implementation
public:
int m_nTimeOut;
virtual ~CSocket();
static int PASCAL ProcessAuxQueue();
virtual BOOL Accept(CAsyncSocket& rConnectedSocket,
SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL);
virtual void Close();
virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0);
virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);
int SendChunk(const void* lpBuf, int nBufLen, int nFlags);
protected:
friend class CSocketWnd;
BOOL* m_pbBlocking;
int m_nConnectError;
virtual BOOL ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen);
virtual int ReceiveFromHelper(void* lpBuf, int nBufLen,
SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags);
virtual int SendToHelper(const void* lpBuf, int nBufLen,
const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags);
static void PASCAL AuxQueueAdd(UINT message, WPARAM wParam, LPARAM lParam);
virtual BOOL PumpMessages(UINT uStopFlag);
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
};
CAsyncSocket类定义
// CAsyncSocket
class CAsyncSocket : public CObject
{
DECLARE_DYNAMIC(CAsyncSocket);
private:
CAsyncSocket(const CAsyncSocket& rSrc); // no implementation
void operator=(const CAsyncSocket& rSrc); // no implementation
// Construction
public:
CAsyncSocket();
BOOL Create(UINT nSocketPort = 0, int nSocketType=SOCK_STREAM,
long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
LPCTSTR lpszSocketAddress = NULL);
BOOL CreateEx(ADDRINFOT* pAI,
long lEvent = FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
// Attributes
public:
SOCKET m_hSocket;
operator SOCKET() const;
BOOL Attach(SOCKET hSocket, long lEvent =
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
SOCKET Detach();
BOOL GetPeerName(CString& rPeerAddress, UINT& rPeerPort);
BOOL GetPeerName(SOCKADDR* lpSockAddr, int* lpSockAddrLen);
BOOL GetPeerNameEx(CString& rPeerAddress, UINT& rPeerPort);
BOOL GetSockName(CString& rSocketAddress, UINT& rSocketPort);
BOOL GetSockName(SOCKADDR* lpSockAddr, int* lpSockAddrLen);
BOOL GetSockNameEx(CString& rSocketAddress, UINT& rSocketPort);
BOOL SetSockOpt(int nOptionName, const void* lpOptionValue,
int nOptionLen, int nLevel = SOL_SOCKET);
BOOL GetSockOpt(int nOptionName, void* lpOptionValue,
int* lpOptionLen, int nLevel = SOL_SOCKET);
static CAsyncSocket* PASCAL FromHandle(SOCKET hSocket);
static int PASCAL GetLastError();
// Operations
public:
virtual BOOL Accept(CAsyncSocket& rConnectedSocket,
SOCKADDR* lpSockAddr = NULL, int* lpSockAddrLen = NULL);
BOOL Bind(UINT nSocketPort, LPCTSTR lpszSocketAddress = NULL);
BOOL Bind (const SOCKADDR* lpSockAddr, int nSockAddrLen);
BOOL BindEx(ADDRINFOT* pAI);
virtual void Close();
BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort);
BOOL Connect(const SOCKADDR* lpSockAddr, int nSockAddrLen);
BOOL ConnectEx(ADDRINFOT* pAI);
BOOL IOCtl(long lCommand, DWORD* lpArgument);
BOOL Listen(int nConnectionBacklog=5);
virtual int Receive(void* lpBuf, int nBufLen, int nFlags = 0);
int ReceiveFrom(void* lpBuf, int nBufLen,
CString& rSocketAddress, UINT& rSocketPort, int nFlags = 0);
int ReceiveFrom(void* lpBuf, int nBufLen,
SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags = 0);
int ReceiveFromEx(void* lpBuf, int nBufLen,
CString& rSocketAddress, UINT& rSocketPort, int nFlags = 0);
enum { receives = 0, sends = 1, both = 2 };
BOOL ShutDown(int nHow = sends);
virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);
int SendTo(const void* lpBuf, int nBufLen,
UINT nHostPort, LPCTSTR lpszHostAddress = NULL, int nFlags = 0);
int SendTo(const void* lpBuf, int nBufLen,
const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags = 0);
int SendToEx(const void* lpBuf, int nBufLen,
UINT nHostPort, LPCTSTR lpszHostAddress = NULL, int nFlags = 0);
BOOL AsyncSelect(long lEvent =
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
// Overridable callbacks
protected:
virtual void OnReceive(int nErrorCode);
virtual void OnSend(int nErrorCode);
virtual void OnOutOfBandData(int nErrorCode);
virtual void OnAccept(int nErrorCode);
virtual void OnConnect(int nErrorCode);
virtual void OnClose(int nErrorCode);
// Implementation
public:
virtual ~CAsyncSocket();
static CAsyncSocket* PASCAL LookupHandle(SOCKET hSocket, BOOL bDead = FALSE);
static void PASCAL AttachHandle(SOCKET hSocket, CAsyncSocket* pSocket, BOOL bDead = FALSE);
static void PASCAL DetachHandle(SOCKET hSocket, BOOL bDead = FALSE);
static void PASCAL KillSocket(SOCKET hSocket, CAsyncSocket* pSocket);
static void PASCAL DoCallBack(WPARAM wParam, LPARAM lParam);
BOOL Socket(int nSocketType=SOCK_STREAM, long lEvent =
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE,
int nProtocolType = 0, int nAddressFormat = PF_INET);
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
friend class CSocketWnd;
virtual BOOL ConnectHelper(const SOCKADDR* lpSockAddr, int nSockAddrLen);
virtual int ReceiveFromHelper(void* lpBuf, int nBufLen,
SOCKADDR* lpSockAddr, int* lpSockAddrLen, int nFlags);
virtual int SendToHelper(const void* lpBuf, int nBufLen,
const SOCKADDR* lpSockAddr, int nSockAddrLen, int nFlags);
};
流程说明
序号 | 服务端 | 客户端 |
1 | 构造一个套接字 CAsyncSocket sockServer | 构造一个套接字 CAsyncSocket sockClient |
2 | 创建SOCKET句柄,绑定到指定的端口 sockServer.Create(nPort); | 创建SOCKET句柄,使用默认参数 sockClient.Create(); |
3 | 启动监听,时刻准备接收连接请求 sockServer.Listen(); | |
4 | 请求链接服务器 sockClient.Connect(strAddress,nPort) | |
5 | 构造一个新的空套接字 CAsyncSocket sockRecv; 接收连接 sockServer.Accept(sockRecv); | |
6 | 接收数据 sockRecv.Receive(pBuffer,nLen); | 发送连接 sockClient.Send(pBuffer,nLen); |
7 | 发送数据 sockRecv.Send(pBuffer,nLen); | 接收数据 sockClient.Receive(pBuffer,nLen); |
8 | 关闭套接字对象 sockRecv.Close(); | 关闭套接字对象 sockClient.Close(); |