主要理解select函数,涉及到一些 宏和 数组定义
分为两端
Server端:
// soctet_server.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
SOCKET gClientSockAddr[FD_SETSIZE]={0};
DWORD gClientSockNum = 0;
HANDLE ghMutex = NULL;
DWORD WINAPI RecvSendThead(LPVOID lpvoid);
DWORD WINAPI RecvSendThead(LPVOID lpvoid)
{
timeval timeout = {3,0};
while(TRUE)
{
DWORD ClientSockNum = gClientSockNum;
if(ClientSockNum)
{
FD_SET readset;
FD_ZERO (&readset);
for(DWORD i=0;i<ClientSockNum;i++)
{
FD_SET(gClientSockAddr[i],&readset);
}
int ReadableNum = select(0,&readset,NULL,NULL,&timeout);
if(ReadableNum == 0)
{
continue;
}else{
for(DWORD k = 0;k<ClientSockNum;k++)
{
if(FD_ISSET(gClientSockAddr[k],&readset))
{
char buf[MAX_PATH] = {0};
int recvlen = recv(gClientSockAddr[k],buf,MAX_PATH,0);
//if(strcmp(buf,"quit") == 0)
if(strcmp(buf,"quit") == 0)
{
//断开
shutdown(gClientSockAddr[k],SD_SEND);
closesocket(gClientSockAddr[k]);
WaitForSingleObject(ghMutex,INFINITE);
gClientSockAddr[k] = gClientSockAddr[gClientSockNum-1];
gClientSockAddr[gClientSockNum - 1] = NULL;
gClientSockNum-=1;
ReleaseMutex(ghMutex);
}
if(recvlen ==0 || recvlen == -1)
{
//断开
shutdown(gClientSockAddr[k],SD_SEND);
closesocket(gClientSockAddr[k]);
WaitForSingleObject(ghMutex,INFINITE);
gClientSockAddr[k] = gClientSockAddr[gClientSockNum-1];
gClientSockAddr[gClientSockNum - 1] = NULL;
gClientSockNum-=1;
ReleaseMutex(ghMutex);
}else{
printf("Client Message: %s\n",buf);
send(gClientSockAddr[k],buf,strlen(buf)+1,0);
memset(buf,0,MAX_PATH);
}
}
}
}
}
}
return 0;
}
int main(int argc, char* argv[])
{
//0:初始化
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return 0;
}
//1 create socket
SOCKET hSerSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//2 bind
struct sockaddr_in SerAddr={0};
SerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
SerAddr.sin_family = AF_INET;
SerAddr.sin_port = htons(2018);
bind(hSerSocket,(sockaddr*)&SerAddr,sizeof(SerAddr));
//3 listen
listen(hSerSocket,5);
//4 accept
ghMutex = CreateMutex(NULL,FALSE,NULL);
HANDLE hThread = CreateThread(NULL,0,RecvSendThead,NULL,0,NULL);
CloseHandle(hThread);
while(TRUE)
{
struct sockaddr ClientAddr={0};
int ClientAddrLen = sizeof(sockaddr);
SOCKET hClientSocket = accept(hSerSocket,(sockaddr*)&ClientAddr,&ClientAddrLen);
WaitForSingleObject(ghMutex,INFINITE);
gClientSockAddr[gClientSockNum++] = hClientSocket;
printf("第 %d 个客户进来\n",gClientSockNum);
ReleaseMutex(ghMutex);
}
//5 send recv
closesocket(hSerSocket);
WSACleanup();
return 0;
}
Client客户端
// socket_client.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Winsock2.h>
#pragma comment(lib,"Ws2_32.lib")
int main(int argc, char* argv[])
{
/*
创建套接字
绑定套接字
连接服务器
收发数据
断开连接(主动)
关闭套接字
*/
//0:初始化
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 ) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return 0;
}
//1 create socket
SOCKET hCliSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//2 connet
struct sockaddr_in SerAddr={0};
SerAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
SerAddr.sin_family = AF_INET;
SerAddr.sin_port = htons(2018);
connect(hCliSocket,(sockaddr*)&SerAddr,sizeof(SerAddr));
//3 send/recv
char sendBuf[100]={0};
while(TRUE)
{
scanf("%s",&sendBuf);
if(strcmp(sendBuf,"quit")==0)
{
break;
}
send(hCliSocket,sendBuf,strlen(sendBuf)+1,0);
char recvBuf[100]={0};
recv(hCliSocket,recvBuf,100,0);
printf("client: %s\n",recvBuf);
}
shutdown(hCliSocket,SD_RECEIVE);
closesocket(hCliSocket);
return 0;
}