select加线程的服务端代码

来源:互联网 发布:大数据是以hadoop 编辑:程序博客网 时间:2024/06/07 18:09

服务端:

#include"stdafx.h"


#include <WinSock2.h>  
#include <iostream>  
using namespace std;
 
#pragma comment(lib,"Ws2_32.lib")  


//存储所有的客户端套接字
fd_set   g_fdClientSock;


//线程函数声明
DWORD WINAPI  ThreadProc(LPVOID lpParameter);




int main()
{
// 初始化Winsock 2.2
WSAData wsaData;
if (0 != WSAStartup(MAKEWORD(2, 2), &wsaData))
{
cout << "WSAStartup  error:" << WSAGetLastError()<<endl; 
return -1;
}


   //创建监听套接字
SOCKET  sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sListen == INVALID_SOCKET)
{
cout << "socket() Error: " << WSAGetLastError() << endl;return  0;
}


sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8000);
sin.sin_addr.S_un.S_addr = ADDR_ANY;  
//绑定到本机任意地址
if (SOCKET_ERROR == bind(sListen, (sockaddr*)&sin, sizeof(sin)))
{
cout << "bind  error:" << WSAGetLastError() << endl; 
return -1;
}


//监听套接字
if (listen(sListen, 5) == SOCKET_ERROR)
{
cout << " listen() Error:" << WSAGetLastError() << endl;
return  0;
}


 
//创建一个线程,利用select即可处理多个客户端
HANDLE hThread = CreateThread(NULL, 0, ThreadProc, NULL, 0, NULL);
CloseHandle(hThread);//关闭对线程的引用 


//1)初始化一个套接字集合fdSocket,并将监听套接字放入  
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(sListen, &readSet);  


while (true)

//同时检查套接字的可读可写性。
int  ret= select(0, &readSet, NULL, NULL, NULL);//若不设置超时则select为阻塞  
if (ret >0)   //-1
{
//是否存在客户端的连接请求。  
if (FD_ISSET(sListen, &readSet))//在readset中会返回已经调用过listen的套接字。  
{
//是否超过限制
if (g_fdClientSock.fd_count < FD_SETSIZE)
{
sockaddr_in addrRemote;
int nAddrLen = sizeof(sockaddr);
SOCKET sClient = accept(sListen, (sockaddr*)&addrRemote, &nAddrLen);

if (sClient != INVALID_SOCKET)
{
FD_SET(sClient, &g_fdClientSock); 


cout << sClient << "进入聊天室!" << endl;
char tmp[64];
sprintf(tmp, "欢迎%d进入聊天室!", sClient);
send(sClient, tmp, strlen(tmp), 0);
}
}
 



}
else if (ret == 0)
{
cout<<"selct time out!"<<endl;
}
else
{
cout << "select  error:" << WSAGetLastError() << endl;
}


Sleep(1000);


}


//关闭套接字
closesocket(sListen);




// 最后应该做一些清除工作
if (WSACleanup() == SOCKET_ERROR)
{
cout << "WSACleanup 出错!" << endl;
}


}






//线程中接收与发送消息
DWORD WINAPI  ThreadProc(LPVOID lpParameter)
{




fd_set fdRead;
FD_ZERO(&fdRead); 


char buf[64] ; 


while (true)
{
//将客户端套接字集合赋值给fdRead
fdRead = g_fdClientSock;
int  nRet = select(0, &fdRead, NULL, NULL, NULL);
if (nRet != SOCKET_ERROR)
{
//遍历集合,检查套接字是否还在
for (int i = 0; i < g_fdClientSock.fd_count; i++)
{
if (FD_ISSET(g_fdClientSock.fd_array[i], &fdRead))
{
SOCKET c = g_fdClientSock.fd_array[i];


memset(buf, 0, 64);
nRet = recv(c, buf, 64, 0);
if (nRet == SOCKET_ERROR)

   closesocket(g_fdClientSock.fd_array[i]);
FD_CLR(c, &g_fdClientSock);
cout << c << "离开了!" << endl;
}
else
{
cout << c << "说: " << buf << endl;
}
}
}
}
}
 

return 0;
}




客户端



// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include<winsock2.h> 
#pragma comment(lib, "ws2_32.lib")


#include <iostream>
using namespace  std;




int main()
{
// WSADATA 结构体主要包含了系统所支持的Winsock版本信息
WSADATA wsaData;
// 初始化Winsock 2.2
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup 无法初始化!" << endl;
return 0;
}




SOCKET  s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
cout << "socket() Error: " << WSAGetLastError() << endl;
return  0;



struct sockaddr_in    addr;
addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(8000); 


if (connect(s, (SOCKADDR*)&addr, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
cout << "connect() Error: " << WSAGetLastError() << endl;



//接收服务端的信息
char buf[64];
memset(buf, 0, 64);
    recv(s, buf, 64, 0);
cout << buf << endl;




int  ret = 0;
do
{
char buf[64];
cout << "请输入聊天内容:" ;
cin >> buf ;
ret = send(s,  buf , strlen( buf), 0);  


} while (ret != SOCKET_ERROR  &&  ret != 0);


 



closesocket(s);




// 最后应该做一些清除工作
if (WSACleanup() == SOCKET_ERROR)
{
cout << "WSACleanup 出错!" << endl;
}






return 0;
}


原创粉丝点击