Linux下基于socket和多線程的聊天室小程序

轉載:http://blog.csdn.net/robot__man/article/details/52460733

要求:基于TCP編寫,一個聊天室最多100人。?
客戶端:?
  1、用戶需要登錄,登錄時只需要輸入一個昵稱即可無需判斷昵稱是否重復(如果其他功能都ok考慮)?
  2、用戶登錄后連接服務器端,進入聊天室?
  3、用戶可以輸入聊天信息,也可以收到別人的聊天信息。?
  4、用戶可以用某個特殊單詞代表退出聊天室。

服務器端:?
  1、啟動服務器,開放端口?
  2、等待客戶端的連接,每連接上一個客戶端,啟動一個線程?
  3、在線程中與客戶端交互,交互過程:如果有客戶端登錄、退出、提交聊天,都應該發給所有的客戶端。需要   保存所有客戶端。

額外功能:可以考慮實現TCP的文件傳輸。

server.c#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pthread.h>int sockfd;//服務器socket
int fds[100];//客戶端的socketfd,100個元素,fds[0]~fds[99]
int size =100 ;//用來控制進入聊天室的人數為100以內
char* IP = "192.168.10.143";
short PORT = 10222;
typedef struct sockaddr SA;void init(){sockfd = socket(PF_INET,SOCK_STREAM,0);if (sockfd == -1){perror("創建socket失敗");exit(-1);}struct sockaddr_in addr;addr.sin_family = PF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = inet_addr(IP);if (bind(sockfd,(SA*)&addr,sizeof(addr)) == -1){perror("綁定失敗");exit(-1);}if (listen(sockfd,100) == -1){perror("設置監聽失敗");exit(-1);}
}void SendMsgToAll(char* msg){int i;for (i = 0;i < size;i++){if (fds[i] != 0){printf("sendto%d\n",fds[i]);send(fds[i],msg,strlen(msg),0);}}
}void* service_thread(void* p){int fd = *(int*)p;printf("pthread = %d\n",fd);while(1){char buf[100] = {};if (recv(fd,buf,sizeof(buf),0) <= 0){int i;for (i = 0;i < size;i++){if (fd == fds[i]){fds[i] = 0;break;}}printf("退出:fd = %dquit\n",fd);pthread_exit((void*)i);}//把服務器接受到的信息發給所有的客戶端SendMsgToAll(buf);}
}void service(){printf("服務器啟動\n");while(1){struct sockaddr_in fromaddr;socklen_t len = sizeof(fromaddr);int fd = accept(sockfd,(SA*)&fromaddr,&len);if (fd == -1){printf("客戶端連接出錯...\n");continue;}int i = 0;for (i = 0;i < size;i++){if (fds[i] == 0){//記錄客戶端的socketfds[i] = fd;printf("fd = %d\n",fd);//有客戶端連接之后,啟動線程給此客戶服務pthread_t tid;pthread_create(&tid,0,service_thread,&fd);break;}if (size == i){//發送給客戶端說聊天室滿了char* str = "對不起,聊天室已經滿了!";send(fd,str,strlen(str),0); close(fd);}}}
}int main(){init();service();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
client.c#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>int sockfd;//客戶端socket
char* IP = "192.168.10.143";//服務器的IP
short PORT = 10222;//服務器服務端口
typedef struct sockaddr SA;
char name[30];void init(){sockfd = socket(PF_INET,SOCK_STREAM,0);struct sockaddr_in addr;addr.sin_family = PF_INET;addr.sin_port = htons(PORT);addr.sin_addr.s_addr = inet_addr(IP);if (connect(sockfd,(SA*)&addr,sizeof(addr)) == -1){perror("無法連接到服務器");exit(-1);}printf("客戶端啟動成功\n");
}void start(){pthread_t id;void* recv_thread(void*);pthread_create(&id,0,recv_thread,0);char buf2[100] = {};sprintf(buf2,"%s進入了聊天室",name);send(sockfd,buf2,strlen(buf2),0);while(1){char buf[100] = {};scanf("%s",buf);char msg[131] = {};sprintf(msg,"%s:%s",name,buf);send(sockfd,msg,strlen(msg),0);if (strcmp(buf,"bye") == 0){memset(buf2,0,sizeof(buf2));sprintf(buf2,"%s退出了聊天室",name);send(sockfd,buf2,strlen(buf2),0);break;}}close(sockfd);
}void* recv_thread(void* p){while(1){char buf[100] = {};if (recv(sockfd,buf,sizeof(buf),0) <= 0){return;}printf("%s\n",buf);}
}int main(){init();printf("請輸入您的名字:");scanf("%s",name);start();return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

  剛開始,我聲明的那個全局數組int fds[99],它是有99個元素,fds[0]~fds[98],我以為是到fds[99],結果數組越界,向fds[99]指向的未知文件描述符發了個數據,而fds[99]指向的是監視進程的,向它發任何數據,進程都會莫名奇妙的終止。于是,服務器莫名奇妙的掛掉了,朋友用gdb調試,才發現Program received signal SIGPIPE, Broken pipe.這個問題我自己看了一天半也沒發現,最后還是在群里面,別人幫提出來的,感悟有以下幾點:?
1、Linux下寫程序,也有調試工具gdb,要學會使用,程序出錯了,如果看不出來,就可以來調試;?
2、程序員不是一直埋頭寫程序就行了,還是要多和別人交流,一切以解決問題為根本。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384313.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384313.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384313.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

操作系統(一)計算機系統概述

操作系統&#xff08;一&#xff09;計算機系統概述一、操作系統的概念二、功能和目標資源的管理者向上層提供服務對硬件的擴展三、操作系統的特征并發共享虛擬異步四、操作系統的發展與分類手工操作階段批處理階段單道批處理系統多道批處理系統分時操作系統實時操作系統操作系…

Linux下使用socket傳輸文件的C語言簡單實現

轉載&#xff1a;http://blog.csdn.net/ljd_1986413/article/details/7940938 服務器程序和客戶端程序應當分別運行在兩臺計算機上。 在運行服務器端的計算機終端執行&#xff1a;./file_server 在運行客戶端的計算終端上執行&#xff1a;./file_client ipaddr_server 然后根…

操作系統(二)進程管理

ui 操作系統&#xff08;二&#xff09;進程管理一、進程程序和進程進程控制塊&#xff08;PCB&#xff09;進程的組成進程的特征進程的狀態與轉換進程狀態的轉換進程的組織鏈接方式索引方式進程的控制進程的創建進程的終止進程阻塞進程喚醒進程切換進程通信共享存儲消息傳遞管…

gethostbyname()函數說明

轉載&#xff1a;http://www.cnblogs.com/cxz2009/archive/2010/11/19/1881611.html gethostbyname()函數說明——用域名或主機名獲取IP地址 包含頭文件 #include <netdb.h> #include <sys/socket.h> 函數原型 struct hostent *gethostbyna…

操作系統(三)內存管理

操作系統&#xff08;三&#xff09;內存管理一、程序執行過程裝入的三種方式鏈接的三種方式二、內存管理的概念內存空間的分配與回收連續分配管理方式單一連續分配固定分區分配動態分區分配首次適應算法最佳適應算法最壞適應算法鄰近適應算法非連續分配管理方式基本分頁存儲管…

操作系統(四)文件管理

操作系統&#xff08;四&#xff09;文件管理一、文件系統基礎1.文件邏輯結構無結構文件有結構文件2.文件目錄文件控制塊&#xff08;FCB&#xff09;目錄結構單級目錄兩級目錄結構多級目錄結構無環圖目錄結構3.文件保護口令保護加密保護訪問控制4.文件共享硬鏈接軟鏈接5.文件系…

struct stat結構體簡介

轉載&#xff1a;http://www.cnblogs.com/CSU-PL/archive/2013/06/06/3120757.html 在使用這個結構體和方法時&#xff0c;需要引入&#xff1a; <sys/types.h> <sys/stat.h> struct stat這個結構體是用來描述一個linux系統文件系統中的文件屬性的結構。 可以有兩種…

如何在Ubuntu上安裝GCC編譯器

如何在Ubuntu上安裝GCC編譯器1.首先更新包列表sudo apt update2.安裝build-essential軟件包&#xff1a; sudo apt install build-essential3.驗證GCC編譯器是否已成功安裝&#xff0c;請使用gcc --version命令打印GCC版本 rootubuntu:/home/csd# gcc --version

操作系統(五)輸入/輸出(I/O)管理

操作系統&#xff08;五&#xff09;輸入/輸出&#xff08;I/O&#xff09;管理一、I/O控制器二、I/O控制方式程序直接控制方式中斷驅動方式DMA方式通道控制方式I/O軟件層次結構假脫機技術設備的分配與回收緩沖區單緩沖雙緩沖循環緩沖區緩沖池一、I/O控制器 I/O設備由機械部件…

Linux下的I/O多路復用select,poll,epoll淺析

轉載&#xff1a;http://blog.csdn.net/u011573853/article/details/52105365 一&#xff0c;什么是I/O多路復用 所謂的I/O多路復用在英文中其實叫 I/O multiplexing. 就是單個線程&#xff0c;通過記錄跟蹤每個I/O流(sock)的狀態&#xff0c;來同時管理多個I/O流 。) I/O mu…

計算機組成原理(一)計算機系統概述

計算機組成原理&#xff08;一&#xff09;計算機系統概述一、計算機系統層次結構馮諾伊曼機計算機工作過程多級層次結構一、計算機系統層次結構 馮諾伊曼機 特點&#xff1a; 計算機由五大部件組成指令和數據以同等地位存于存儲 器&#xff0c;可按地址尋訪指令和數據用二進…

計算機組成原理(二)數據的表示和運算

計算機組成原理&#xff08;二&#xff09;數據的表示和運算一、BCD碼二、奇偶校驗碼三、海明碼四、循環冗余校驗碼&#xff08;CRC&#xff09;五、乘法運算原碼乘法補碼乘法六、除法運算原碼除法補碼除法七、浮點數的表示與運算浮點數的運算一、BCD碼 組合式BCD碼&#xff1…

select read write

轉載&#xff1a;http://blog.csdn.net/beginning1126/article/details/8057498 [cpp] view plaincopy <p style"color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px; text-align: left; "><span style"font-size:14px;…

數據結構(七)圖的遍歷(遞歸非遞歸方法)

圖的遍歷&#xff08;遞歸非遞歸方法&#xff09;#include<iostream> #include<stdio.h> #include<stack> #include<queue> using namespace std;typedef char VertexType; typedef int EdgeType;#define MAXVEX 100 #define INF 65535 bool visited[M…

Linux IO復用區別與epoll詳解

轉載&#xff1a;http://blog.csdn.net/hacker00011000/article/details/52160590 一、select、poll、epoll之間的區別總結[整理]   select&#xff0c;poll&#xff0c;epoll都是IO多路復用的機制。I/O多路復用就通過一種機制&#xff0c;可以監視多個描述符&#xff0c;一…

簡單圖和多重圖

一、簡單圖 ?? ① 不存在重復邊&#xff1b; ?? ② 不存在頂點到自身的邊&#xff1b; 二、多重圖 ??① 某兩結點之間邊數多于一條&#xff1b; ??② 允許頂點通過一條邊和自己關聯&#xff1b;

C++筆記:select多路復用機制

轉載&#xff1a;http://blog.csdn.net/qdx411324962/article/details/42499535 函數作用&#xff1a; 系統提供select函數來實現多路復用輸入/輸出模型。select系統調用是用來讓我們的程序監視多個文件句柄的狀態變化的。程序會停在select這里等待&#xff0c;直到被監視的文件…

交叉編譯執行應用程序出現:No such file or directory

問題分析 當我在arm板子上執行交叉編譯過的程序的時候發現了這個錯誤。通過百度查詢基本都是缺少32位庫什么的,但是都不能解決問題。 然后我用ll指令&#xff0c;也排除了權限的原因。 我們用ldd指令發現&#xff0c;它不是動態執行的&#xff0c;雖然我們可以使用-static指…

select、poll、epoll 比較

轉載&#xff1a;http://blog.csdn.net/dodo_328/article/details/39081183 1.Selet&#xff1a;本質上是通過設置或者檢查存放fd標志位的數據結構來進行下一步處理。 缺點&#xff1a;1 單個進程可監視的fd數量被限制&#xff0c;因為受描述符集合fd_set限制&#xff0c;fd數量…

C庫函數 File

C庫函數常用的有&#xff1a;fopen, fclose, fread, fwrite, fgets, fputs, fscanf, fprintf, fseek, fgetc, fputc, ftell, feof, flush等&#xff0c; 當使用fopen打開一個文件時通常返回一個文件指針 FILE *fp。FILE類型是一個結構體&#xff0c;包含文件描述符&#xff08;…