SOCKET与 线程 完成聊天室 (服务端)

来源:互联网 发布:ubuntu中怎么安装qq 编辑:程序博客网 时间:2024/06/05 21:50

CSocket.h     文件


#ifndef __CSOCKET_H__#define __CSOCKET_H__#include <windows.h>#include "SocketEnum.h"#include <iostream>using namespace std;#include "ClientList.h"class CSocket{public:CSocket(SocketEnum::SocketType _socketType=SocketEnum::Tcp);~CSocket();bool Connect(const char* ip,int port);//链接 int Send(char* pBuf,int len);//发送int Receive(int strLen);//接收bool SetBlocking(bool isBlocking);//设置阻塞模式bool ShutDown(SocketEnum::ShutdownMode mode);char* GetData();//获取接收数据SocketEnum::SocketError GetSocketError();void SetSocketHandle(SOCKET socket);void Close(); bool operator==(const CSocket* socket);bool IsExit();private: void SetSocketError(SocketEnum::SocketError error);//设置错误信息void SetSocketError(void);bool IsSocketValid(void);SOCKET csocket;bool isConnected;//链接状态struct sockaddr_in serverAddress; char* buffer;//存接收数据int sendCount;//发送数据长度int recvCount;//接收数据长度 bool isBlocking;//是否是阻塞模式SocketEnum::SocketError socketError;SocketEnum::SocketType socketType; WSADATA wsa;};#endif


CSocket.cpp    文件


#include "CSocket.h"CSocket::CSocket(SocketEnum::SocketType _socketType):csocket(INVALID_SOCKET),isConnected(false),buffer(NULL),sendCount(0),recvCount(0),isBlocking(true),socketError(SocketEnum::InvalidSocket),socketType(_socketType) {} bool CSocket::Connect(const char* ip,int port){isConnected=true;socketError=SocketEnum::Success;if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)//初始化套接字DLL{SetSocketError(SocketEnum::WSAStartupError); isConnected=false;}if(isConnected){if((csocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){SetSocketError();isConnected=false;}}if(isConnected){memset(&serverAddress,0,sizeof(sockaddr_in));serverAddress.sin_family=AF_INET;long lip=inet_addr(ip);if(lip==INADDR_NONE){ SetSocketError(SocketEnum::InvalidAddress);     isConnected=false;} else{if(port<0){SetSocketError(SocketEnum::InvalidPort);isConnected=false;}else{serverAddress.sin_addr.S_un.S_addr= lip;serverAddress.sin_port = htons(port);if(connect(csocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){SetSocketError(); isConnected=false;} }}} return isConnected; }//设置阻塞模式bool CSocket::SetBlocking(bool isBlock){int block=isBlock?0:1;if (ioctlsocket(csocket, FIONBIO, (ULONG *)&block) != 0){    return false;}isBlocking=isBlock;return true;} int CSocket::Send(char* pBuf,int len){if(!IsSocketValid() || !isConnected){return 0;}if(pBuf==NULL || len<1){return 0;}sendCount=send(csocket,pBuf,len,0);if(sendCount<=0){cout<<GetSocketError()<<endl;}return sendCount; } int CSocket::Receive(int strLen){recvCount=0;if(!IsSocketValid() || !isConnected){return recvCount;} if(strLen<1){return recvCount;} if(buffer!=NULL){delete buffer;buffer=NULL;} buffer=new char[strLen];SetSocketError(SocketEnum::Success); while(1){recvCount=recv(csocket,buffer,strLen,0) ; if(recvCount>0){buffer[recvCount]='\0';if(IsExit()){Send(buffer,recvCount);delete buffer;buffer=NULL;recvCount=0; break;}else{cout<<buffer<<endl;}}} return recvCount;}bool CSocket::IsExit(){int len=strlen(buffer);int i=0;int size=4;if(len==size){char* exit="EXIT"; for(i=0;i<size;i++){if(buffer[i]!=*(exit+i) && buffer[i]-32!=*(exit+i)){break;}}}return i==size;}//设置错误信息void CSocket::SetSocketError(SocketEnum::SocketError error){socketError=error;}void CSocket::SetSocketError(void){     int nError = WSAGetLastError();    switch (nError)    {        case EXIT_SUCCESS:            SetSocketError(SocketEnum::Success);            break;        case WSAEBADF:        case WSAENOTCONN:            SetSocketError(SocketEnum::Notconnected);            break;        case WSAEINTR:            SetSocketError(SocketEnum::Interrupted);            break;        case WSAEACCES:        case WSAEAFNOSUPPORT:        case WSAEINVAL:        case WSAEMFILE:        case WSAENOBUFS:        case WSAEPROTONOSUPPORT:            SetSocketError(SocketEnum::InvalidSocket);            break;        case WSAECONNREFUSED :            SetSocketError(SocketEnum::ConnectionRefused);            break;        case WSAETIMEDOUT:            SetSocketError(SocketEnum::Timedout);            break;        case WSAEINPROGRESS:            SetSocketError(SocketEnum::Einprogress);            break;        case WSAECONNABORTED:            SetSocketError(SocketEnum::ConnectionAborted);            break;        case WSAEWOULDBLOCK:            SetSocketError(SocketEnum::Ewouldblock);            break;        case WSAENOTSOCK:            SetSocketError(SocketEnum::InvalidSocket);            break;        case WSAECONNRESET:            SetSocketError(SocketEnum::ConnectionReset);            break;        case WSANO_DATA:            SetSocketError(SocketEnum::InvalidAddress);            break;        case WSAEADDRINUSE:            SetSocketError(SocketEnum::AddressInUse);            break;        case WSAEFAULT:            SetSocketError(SocketEnum::InvalidPointer);            break;        default:            SetSocketError(SocketEnum::UnknownError);            break;    } } bool CSocket::IsSocketValid(void){return socketError==SocketEnum::Success;}SocketEnum::SocketError CSocket::GetSocketError(){return socketError;}CSocket::~CSocket(){ Close();}void CSocket::Close(){if(buffer!=NULL){delete buffer;buffer=NULL;}ShutDown(SocketEnum::Both);if( closesocket(csocket)!=SocketEnum::Error){csocket= INVALID_SOCKET;}    /*WSACleanup();//清理套接字占用的资源*/ }bool CSocket::ShutDown(SocketEnum::ShutdownMode mode){ SocketEnum::SocketError nRetVal = (SocketEnum::SocketError)shutdown(csocket, SocketEnum::Both);SetSocketError(); return (nRetVal == SocketEnum::Success) ? true: false;}char* CSocket::GetData(){return buffer;}void CSocket::SetSocketHandle(SOCKET socket){if(socket!=SOCKET_ERROR){csocket=socket;isConnected=true;socketError=SocketEnum::Success;}}bool CSocket::operator==(const CSocket* socket){return csocket==socket->csocket;} 



SocketEnum.h     定义枚举类型


#ifndef __ENUMTYPE_H__#define __ENUMTYPE_H__  struct SocketEnum{typedef enum {Invalid,Tcp,Udp}SocketType;typedef enum {Error = -1,          Success = 0,     InvalidSocket,InvalidAddress,      InvalidPort,           ConnectionRefused,   Timedout,            Ewouldblock,         Notconnected,         Einprogress,         Interrupted,         ConnectionAborted,   ProtocolError,        InvalidBuffer,  ConnectionReset,     AddressInUse,        InvalidPointer ,WSAStartupError,BindError,ListenError,UnknownError} SocketError;typedef enum {Receives  = 0,  Sends  = 1,     Both = 2    } ShutdownMode;   };#endif __ENUMTYPE_H__


ClientList.h  文件


//ClientList.h 存放客户端的请求,只能有一个实例#ifndef _CLIENTLIST_H_#define _CLIENTLIST_H_#include <vector>#include "CSocket.h" #include <assert.h>class CSocket;class ClientList{public : typedef vector<CSocket*>::iterator Iter; void Add(CSocket* socket);int Count() const;CSocket* operator[](size_t index);void Remove(CSocket* socket);Iter Find(CSocket* socket); void Clear(); static ClientList* GetInstance(){static ClientList instance;return &instance;}~ClientList();private:static CRITICAL_SECTION g_cs;static vector<CSocket*> _list; ClientList(); ClientList(const ClientList&);ClientList& operator=(const ClientList&); }; #endif      


ClientList.cpp  文件


#include "ClientList.h"typedef vector<CSocket*>::iterator Iter; ClientList::ClientList(){InitializeCriticalSection(&g_cs);//初始化g_cs的成员 }ClientList::~ClientList(){DeleteCriticalSection(&g_cs);//删除关键段 }void ClientList::Add(CSocket* socket){if(socket!=NULL){EnterCriticalSection(&g_cs);//进入关键段_list.push_back(socket);LeaveCriticalSection(&g_cs);//退出关键段  }}int ClientList::Count() const{return _list.size();}CSocket* ClientList::operator[](size_t index){ assert(index>=0 && index<_list.size()); return _list[index];}void ClientList::Remove(CSocket* socket){ Iter iter=Find(socket);EnterCriticalSection(&g_cs);//进入关键段if(iter!=_list.end()){ delete *iter; _list.erase(iter);}LeaveCriticalSection(&g_cs);//退出关键段  }Iter ClientList::Find(CSocket* socket){EnterCriticalSection(&g_cs);//进入关键段Iter iter=_list.begin();while(iter!=_list.end()){if(*iter==socket){return iter;}iter++;}LeaveCriticalSection(&g_cs);//退出关键段  return iter;}void ClientList::Clear(){EnterCriticalSection(&g_cs);//进入关键段for(int i=_list.size()-1;i>=0;i--){delete _list[i];}_list.clear();LeaveCriticalSection(&g_cs);//退出关键段  }CRITICAL_SECTION ClientList::g_cs;vector<CSocket*> ClientList::_list ;


SServer.h   文件

#ifndef __SSERVER_H__#define __SSERVER_H__#include <windows.h>#include "SocketEnum.h"#include "CSocket.h"class SServer{public://启动服务器bool Start(int port);//接收客户端请求CSocket* Accept(); void SetSocketError(SocketEnum::SocketError error);~SServer();void Close();bool ShutDown(SocketEnum::ShutdownMode mode);private: SOCKET ssocket;char* buffer;struct sockaddr_in serverAddress;SocketEnum::SocketError socketError;bool isStart;WSADATA wsa;};#endif __SSERVER_H__

SServer.cpp    文件


#include "SServer.h"bool SServer::Start(int port){isStart=true;if(WSAStartup(MAKEWORD(2,2),&wsa)!=0)//初始化套接字DLL{SetSocketError(SocketEnum::WSAStartupError); isStart=false;}if(isStart){ if((ssocket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET){SetSocketError(SocketEnum::InvalidSocket);isStart=false;} }if(isStart){//初始化指定的内存区域memset(&serverAddress,0,sizeof(sockaddr_in));serverAddress.sin_family=AF_INET;serverAddress.sin_addr.S_un.S_addr = htonl(INADDR_ANY);if(port>0){serverAddress.sin_port = htons(port);}else{SetSocketError(SocketEnum::InvalidPort);isStart=false;}}if(isStart){//绑定if(bind(ssocket,(sockaddr*)&serverAddress,sizeof(serverAddress))==SOCKET_ERROR){SetSocketError(SocketEnum::BindError);}else{if(listen(ssocket,SOMAXCONN)==SOCKET_ERROR)//进入侦听状态{ SetSocketError(SocketEnum::ListenError);} }}return isStart; } void SServer::SetSocketError(SocketEnum::SocketError error){socketError=error;} CSocket* SServer::Accept(){CSocket* csocket=new CSocket();struct sockaddr_in clientAddress;//用来和客户端通信的套接字地址int addrlen = sizeof(clientAddress);memset(&clientAddress,0,addrlen);//初始化存放客户端信息的内存 SOCKET socket;if((socket=accept(ssocket,(sockaddr*)&clientAddress,&addrlen))!=INVALID_SOCKET){csocket->SetSocketHandle(socket);} return csocket;} SServer::~SServer(){Close();} bool SServer::ShutDown(SocketEnum::ShutdownMode mode){ SocketEnum::SocketError nRetVal = (SocketEnum::SocketError)shutdown(ssocket, SocketEnum::Both); return (nRetVal == SocketEnum::Success) ? true: false;} void SServer::Close(){ShutDown(SocketEnum::Both);if( closesocket(ssocket)!=SocketEnum::Error){ssocket= INVALID_SOCKET;}WSACleanup();//清理套接字占用的资源}



Server.cpp   文件


#include <windows.h>#include <process.h>#include <iostream>using namespace std;#pragma comment(lib,"ws2_32.lib") #include "SServer.h"#include "CSocket.h"#include <vector>#include "ClientList.h"const int BUF_LEN=1024;  void recv(PVOID pt){CSocket* csocket=(CSocket*)pt;if(csocket!=NULL){int count= csocket->Receive(BUF_LEN); if(count==0){  ClientList* list=ClientList::GetInstance(); list->Remove(csocket);cout<<"一个用户下线,在线人数:"<<list->Count()<<endl;_endthread(); //用户下线,终止接收数据线程}} }void sends(PVOID pt){ClientList* list=(ClientList*)pt;while(1){char* buf=new char[BUF_LEN] ;cin>>buf;int bufSize=0;while(buf[bufSize++]!='\0'); for(int i=list->Count()-1;i>=0;i--){(*list)[i]->Send(buf,bufSize);  } delete buf;}} int main(int argc, char* argv[]){SServer server;bool isStart=server.Start(1986);if(isStart){cout<<"server start success..."<<endl;}else{cout<<"server start error"<<endl;} ClientList* list=ClientList::GetInstance();_beginthread(sends,0,list);//启动一个线程广播数据while(1) {CSocket* csocket=server.Accept();list->Add(csocket);cout<<"新上线一个用户,在线人数:"<<list->Count()<<endl;_beginthread(recv,0,csocket);//启动一个接收数据的线程 } getchar();return 0;} 



原创粉丝点击