基于Select模型的匿名聊天室v1.0

最近在无聊完成了一个简单的基于select模型的匿名聊天室程序,均使用C++开发

服务器工作原理:

每接收一条客户端的信息,就将遍历所有的socket,并将该信息发给所有的客户端.

客户端使用两条线程,一个是接收服务端信息的线程,一个是等待阻塞输入的线程,获得输入时,将输入发送到服务器。


项目源码:https://github.com/coderguang/Chat


版本为v2.0的release.


其中ComLib也在github上


服务器核心代码:

int main(int argc,char **argv){
	int i,counter,maxfd,sockfd,listenfd,connfd;
	int nready,client[FD_SETSIZE];
	ssize_t n;
	fd_set rset,allset;
	char buf[MSGSIZE];
	socklen_t clilen;
	
	struct sockaddr_in cliaddr;
	struct sockaddr_in servaddr;
	
	listenfd=Socket(AF_INET,SOCK_STREAM,0);
	
	bzero(&servaddr,sizeof(servaddr));

	servaddr.sin_family=AF_INET;
	servaddr.sin_port=htons(PORT);
	//servaddr.sin_port=htons(atoi(argv[0]));
	servaddr.sin_addr.s_addr=INADDR_ANY;

	Bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));

	Listen(listenfd,10);
	
	maxfd=listenfd; //initialize
	counter=-1;

	for(i=0;i<FD_SETSIZE;i++){
		client[i]=-1;
	}
	
	FD_ZERO(&allset);
	FD_SET(listenfd,&allset);

	for(;;){
		rset=allset;
		nready=Select(maxfd+1,&rset,NULL,NULL,NULL);
	
		if(FD_ISSET(listenfd,&rset)){//new client connecton
			clilen=sizeof(cliaddr);
			connfd=Accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);

			for(i=0;i<FD_SETSIZE;i++){
				if(client[i]<0){
					client[i]=connfd;//save the new sockfd
					break;
				}
			}
			if(i==FD_SETSIZE){
				cout<<"sockfd set full!"<<endl;
			}
			FD_SET(connfd,&allset);//add new to set
			if(connfd>maxfd){
				maxfd=connfd;//for select
			}
			if(i>counter){//max index in client[]
				counter=i;
			}
			if(nready<=0){
				continue; //no more readable
			}

	
		}
		
		for(i=0;i<FD_SETSIZE;i++){//check all clients for data
			if((sockfd=client[i])<0){
				continue;
			}
			if(FD_ISSET(sockfd,&rset)){
				memset(buf,sizeof(buf),'\0');
				if((n=Read(sockfd,buf,MSGSIZE))==0){
					close(sockfd);//connection closed by client
					FD_CLR(sockfd,&allset);
					client[i]=-1;
				}else{
					buf[n]='\0';
					cout<<"get the msg:"<<buf<<endl;
					for(int j=0;j<FD_SETSIZE;j++){
						if(client[j]!=-1)
							Writen(client[j],buf,n);
					}
					
				}
				if(nready<=0){
					break;
				}
			
			}
		}

	}
}

客户端核心代码:

<span style="font-size:18px;">int main(){
    WORD mVersionRequested;
    WSADATA wsaData;//WSADATA结构被用来保存AfxSocketInit函数返回的WindowsSockets初始化信息。
    int ret;

    SOCKET sClient;
    struct sockaddr_in saServer;
    bool fSuccess=true;

    //winSock 初始化

    mVersionRequested=MAKEWORD(2,2);//WinSock dll的版本

    ret=WSAStartup(mVersionRequested,&wsaData);

    if(ret!=0){
        cout<<"WSASartup  failed!"<<endl;
		getchar();
		getchar();
        exit(1);
    }

    if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2){
        WSACleanup();
        cout<<"invaild version"<<endl;
		getchar();
		getchar();
        exit(1);
    }

	sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sClient == INVALID_SOCKET){
		WSACleanup();
		cout << "socket failed" << endl;
		getchar();
		getchar();
		exit(0);
	}



    saServer.sin_family=AF_INET;
    saServer.sin_port=htons(port);
    saServer.sin_addr.S_un.S_addr=inet_addr(host);

    ret=connect(sClient,(struct sockaddr *)&saServer,sizeof(saServer));
    if(ret==SOCKET_ERROR){
        cout<<"连接失败!"<<endl;
        closesocket(sClient);
        WSACleanup();
		getchar();
		getchar();
        exit(1);
    }

	thread recThread(Receive, sClient);
	thread sendThread(ChatInput,sClient);
	recThread.join();
	sendThread.join();

	cout << "over" << endl;
    closesocket(sClient);
    WSACleanup();
	getchar();
	getchar();
	return 0;
}
</span>


重新找工作以来,投了第一家,昨天去面了,9377,感觉还不错,不过感觉自己要价太高了~~~

一个应届生,没有服务端的工作经验,只有半年的U3D实习经验,要8K确实过了,还是太年轻,经验太少啊~~,其实8K只是期望,低点也是无所谓的,6K5我就接受啦~~下午三点笔试面试一直面到了总经理面,到了6点他们总经理还没有空,HR说等他们确定了之后再约,这个确定是神马意思~~~,看来要多投几份了~~~,不过还是挺喜欢9377的,离我现在住的走路地方只要5分钟路程~~~


do hard~~


—————————————————————————————————————————————————————————————————

//写的错误或者不好的地方请多多指导,可以在下面留言或者点击左上方邮件地址给我发邮件,指出我的错误以及不足,以便我修改,更好的分享给大家,谢谢。

转载请注明出处:http://blog.csdn.net/qq844352155

author:天下无双

Email:royalchen@royalchen.com

2015-6-30

于广州天河荷光路

——————————————————————————————————————————————————————————————————



  



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于select模型的TCP聊天室可以使用Python的socket库来实现。该模型允许多个客户端同时连接到服务器,并能够实时交换消息。 首先,服务器端的代码如下: ```python import socket import select # 创建套接字 server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定IP地址和端口号 server_socket.bind(('localhost', 12345)) # 监听连接 server_socket.listen(5) # 创建列表,用于存储连接的客户端套接字 sockets_list = [server_socket] print("聊天室服务器已启动") # 处理消息的函数 def receive_message(client_socket): try: message = client_socket.recv(1024).decode() if message: print("接收到消息: " + message) # 向其他所有客户端发送消息 for socket in sockets_list: if socket != server_socket and socket != client_socket: socket.send(message.encode()) else: # 如果接收到空消息,表示客户端断开连接 sockets_list.remove(client_socket) print("客户端断开连接") client_socket.close() except: pass while True: # 使用select函数监视套接字列表 read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list) # 处理可读套接字 for notified_socket in read_sockets: if notified_socket == server_socket: # 处理新连接 client_socket, client_address = server_socket.accept() sockets_list.append(client_socket) print("新连接: " + client_address[0]) else: # 处理已连接的客户端发送的消息 receive_message(notified_socket) # 处理异常情况下的套接字 for notified_socket in exception_sockets: sockets_list.remove(notified_socket) print("异常套接字关闭") notified_socket.close() ``` 客户端的代码如下: ```python import socket import select import sys client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client_socket.connect(('localhost', 12345)) # 读取用户名 username = input("请输入用户名: ") # 发送用户名到服务器 client_socket.send(username.encode()) print("已连接到聊天室服务器") while True: # 使用select函数监视输入和服务器消息 sockets_list = [sys.stdin, client_socket] read_sockets, _, _ = select.select(sockets_list, [], []) for notified_socket in read_sockets: if notified_socket == client_socket: # 接收服务器消息 message = client_socket.recv(1024).decode() print(message) else: # 发送输入消息到服务器 message = sys.stdin.readline() client_socket.send(message.encode()) sys.stdout.write("<You>") sys.stdout.write(message) sys.stdout.flush() client_socket.close() ``` 以上是一个基于select模型、使用TCP协议的简单聊天室的实现。服务器端可以处理多个客户端的连接和消息传输,客户端可以通过键盘输入发送消息,并接收其他客户端和服务器发来的消息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值