基于TCP的多线程异步socket通信
1、服务端使用socket流程:
1)加载套接字库:WSAStartup (后面要给出具体函数的说明)
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2); //表示调用版本2.2 wVersionRequested结果为512+2=514
//加载套接字库
err = WSAStartup(wVersionRequested, &wsaData); //初始化程序所用的套接字
if (err != 0) { //wsaData用来接收套接字库的实现细节
return FALSE;
}
2)版本号检测:
//版本号检测
if (LOBYTE(wsaData.wVersion) != 2 || //副版本
HIBYTE(wsaData.wVersion) != 2) { //主版本
WSACleanup(); //终止程序对套接字库的使用
return FALSE;
}
3)创建套接字:socket
//创建套接字
m_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
4)绑定套接字:
//绑定套接字
int bindResult;
if (INVALID_SOCKET != m_socket)
{
bindResult = bind(m_socket, (SOCKADDR*)&m_sockAddr, sizeof(SOCKADDR));
}
else
{
MessageBox(_T("创建套接字失败!"));
return FALSE;
}
5)监听套接字:
listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程。在TCP服务器编程中listen函数把进程变为一个服务器,并指定相应的套接字变为被动连接。该函数会阻塞。
//创建监听套接字进程
if (0 == bindResult)
{
m_listenResult = listen(m_socket, 20); //返回值为0则监听成功
}
else
{
MessageBox(_T("绑定套接字失败!"));
return FALSE;
}
6)等待客户连接:accept
AfxBeginThread(AcceptThread, this, 0, 0, 0, THREAD_PRIORITY_NORMAL);
7)接收客户端数据:recv 该函数会阻塞。
char recvBuf[MaxBufSize] = {0};
int recvResult = recv(dlg->m_clientSocket, recvBuf, sizeof(recvBuf), 0);
注意:这里比较容易犯的错误是将接收的套接字m_clientSocket写成服务套接字m_socket。
8)向客户端发送数据:send
char sendBuf[MaxBufSize] = {0};
string sendTest; //这里用string而非CString是因为string型便于转换为const char* 类型
int sendResult = send(dlg->m_clientSocket, sendBuf, sizeof(sendBuf), 0);
注意:用于发送的套接字是accept返回的套接字,而不是用于绑定端口和监听的套接字。
2、客户端使用socket流程
1)加载套接字库:
//加载套接字库
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(2, 2); //表示调用版本2.2 wVersionRequested结果为512+2=514
//加载套接字库
err = WSAStartup(wVersionRequested, &wsaData);//初始化程序所用的套接字
if (