Linux網(wǎng)絡(luò)編程(多人在線聊天系統(tǒng))
一、首先是服務(wù)器的建立
首先是一個(gè)信號(hào)終止程序,發(fā)信號(hào)ctrl+c終止程序,而是是初始化網(wǎng)絡(luò)通信.
創(chuàng)建一個(gè)描述符負(fù)責(zé)綁定服務(wù)器和監(jiān)聽(tīng)服務(wù)器接收客戶端的消息.
socket()->sockaddr_in->bind->listen(準(zhǔn)備就緒)
開(kāi)始接收客戶端消息.start()函數(shù)
首先是聲明一個(gè)結(jié)構(gòu)體用來(lái)存儲(chǔ)客戶端的消息,利用accept()函數(shù)來(lái)創(chuàng)建一個(gè)新的
描述符來(lái)接收,這里有阻塞效果,也即是說(shuō)連接的時(shí)候只能一個(gè)一個(gè)的連.
然后是分離線程處理這個(gè)sockfd的連接.
pthread_create(&pid,0,pthread_deal,&sockfd1);
線程主要是先做線程的分離,然后是取得它們的sockfd描述符,把這個(gè)客戶端的信息
存儲(chǔ)到一個(gè)結(jié)構(gòu)體數(shù)組中.然后是調(diào)用循環(huán)發(fā)送到各個(gè)客戶端的函數(shù),來(lái)發(fā)送消息.
當(dāng)接收函數(shù)recv(sockfd,buf,sizeof(buf)) == 0 的時(shí)候,表示有客戶端退出,這時(shí)
就把這個(gè)在結(jié)構(gòu)體數(shù)組的相應(yīng)的fd置為0
#include "server.h" #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> int sockfd; //服務(wù)器本身的描述符 struct User u[200] = {}; //用來(lái)保存用戶的信息 int size;//數(shù)組的下標(biāo),同時(shí)也是客戶端的個(gè)數(shù) void init(void) //通信準(zhǔn)備工作 { printf("聊天室服務(wù)器馬上啟動(dòng)....\n"); sockfd = socket(AF_INET,SOCK_STREAM,0); if(-1 == sockfd) { perror("fail to socket"); printf("服務(wù)器故障!\n"); exit(-1); } //準(zhǔn)備通信地址和綁定服務(wù)器 struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(2222); //端口的值,轉(zhuǎn)換成網(wǎng)絡(luò)的格式 addr.sin_addr.s_addr = inet_addr("172.16.1.21"); if(-1 == bind(sockfd,(struct sockaddr*)&addr,sizeof(addr))) { perror("fail to bind"); exit(-1); } printf("bind is ok,歡迎訪問(wèn)!\n"); //設(shè)置監(jiān)聽(tīng) if(-1 != listen(sockfd,200)) { printf("監(jiān)聽(tīng)已經(jīng)設(shè)置,一切準(zhǔn)備就緒!\n"); } } void send_msg(char *p_msg) //發(fā)送消息的函數(shù) { int num = 0; for(num = 0;num < size;num++) { if(u[num].fd) //如果是有效的時(shí)候才發(fā)送 { send(u[num].fd,p_msg,sizeof(p_msg),0); } } } void* pthread_deal(void* p) //線程處理函數(shù) { pthread_detach(pthread_self()); int fd2 = *(int*)p; //取得客戶端的sockfd u[size].fd = fd2; //放入結(jié)構(gòu)體中 char name[20] = {}; int res = recv(fd2,name,sizeof(name),0); if(res > 0) { strcpy(u[size].name,name);//存放用戶名 } size++; char user[100] = {}; sprintf(user,"%s悄悄的進(jìn)來(lái)了!(*^__^*) 嘻嘻……\n",name); send_msg(user); while(1) { if(recv(fd2,name,sizeof(name),0) == 0) /*返回0表示有客戶端退出*/ { u[size-1].fd = 0; //把退出的客戶端的結(jié)構(gòu)描述符置換成0 } } } void start(void) { printf("success to start server,let's go!\n"); while(1) { struct sockaddr_in client;//存儲(chǔ)接收到的客戶端的信息 socklen_t length = sizeof(client); //接收客戶端的信息,會(huì)有阻塞效果,sockfd1標(biāo)記客戶端 int sockfd1 = accept(sockfd,(struct sockaddr*)&client,&length); if(sockfd1 == -1) { perror("fail to accept!"); continue; //繼續(xù)連接 } printf("%s連接上來(lái)了\n",inet_ntoa(client.sin_addr)); /*連接成功之后,就啟動(dòng)線程*/ pthread_t pid;//線程id pthread_create(&pid,0,pthread_deal,&sockfd1); } } void sig_exit(int signo ) //子定義信號(hào)關(guān)閉服務(wù)器函數(shù) { close(sockfd);//關(guān)閉服務(wù)器端口 printf("服務(wù)器成功關(guān)閉!\n"); exit(0); } int main(void) { printf("按ctrl+c關(guān)閉聊天室服務(wù)器!\n"); signal(SIGINT,sig_exit); init();//初始化,服務(wù)器通信準(zhǔn)備工作 start();//啟動(dòng)服務(wù)(開(kāi)始處理聊天信息) return 0; }
2.客戶端的編寫.
posted on 2014-07-20 21:07 亞三論 閱讀(3377) 評(píng)論(2) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)