linux使用TCP聊天室设计详解,基于linux的TCP网络聊天室设计与实现
利用Linux實現(xiàn)基于TCP模式的網(wǎng)絡(luò)聊天程序
主要完成的兩大組成部分為:服務(wù)器和客戶端。
服務(wù)器程序主要負(fù)責(zé)監(jiān)聽客戶端發(fā)來的消息。 客戶端需要登錄到服務(wù)器端才可以實現(xiàn)正常的聊天功能。該程序是利用進(jìn)程以及共享內(nèi)存來實現(xiàn)群發(fā)送消息的。
以下簡單分析一下服務(wù)器端和客戶端兩個方面所要完成的任務(wù)。
服務(wù)器的主要功能如下:
在特定的端口上進(jìn)行監(jiān)聽,等待客戶端的連接。 用戶可以配置服務(wù)器端的監(jiān)聽端口。 向連接的客戶端發(fā)送登錄成功信息。 向已經(jīng)連接到服務(wù)器的客戶端的用戶發(fā)送系統(tǒng)消息。 使用TCP多線程并發(fā)服務(wù)器,向在線的所有客戶端發(fā)送消息
客戶端的主要功能如下:
客戶端傳參輸入IP和端口號以及用戶名進(jìn)行注冊 連接到已經(jīng)開啟的服務(wù)的服務(wù)端 用戶可以向所有人發(fā)送信息 用戶可以接受服務(wù)器發(fā)送的系統(tǒng)消息
服務(wù)器功能描述
服務(wù)器主要是負(fù)責(zé)監(jiān)聽客戶端發(fā)送來的消息,利用TCP線程并發(fā)服務(wù)器模型實現(xiàn)對客戶端的監(jiān)聽接收。
服務(wù)器程序的作用為:初始化服務(wù)器程序,持續(xù)監(jiān)聽一個固定的端口,收到客戶的連接后建立一個socket連接,與客戶進(jìn)行通信和信息處理,接收客戶通過socket連接發(fā)送來的數(shù)據(jù),創(chuàng)建一個新的socket;通過socket連接與客戶通信,進(jìn)行響應(yīng)處理,并返回結(jié)果,通信結(jié)束后終端與客戶的連接(關(guān)閉socket);主要的過程為服務(wù)器創(chuàng)建一個共享內(nèi)存空間函數(shù),以及客戶端簡單的界面,利用套接字模型機(jī)制實現(xiàn)服務(wù)器簡易模型的實現(xiàn),利用 socket()創(chuàng)建流式套接字,并可以返回套接自號;利用bind()實現(xiàn)套接字與本地地址相連,listen()通知TCP服務(wù)器準(zhǔn)備好監(jiān)聽客戶端的連接,accept()接收連接,等待客戶端的連接,建立連接之后accept返回新的標(biāo)識客戶端的套接字,運用多線程以及recv()/send()接收發(fā)送數(shù)據(jù);
客戶端功能描述
客戶端主要用來向服務(wù)器端發(fā)送數(shù)據(jù),客戶端程序的作用:初始化客戶程序,連接到某個服務(wù)器上,建立socket連接,通過socket連接向服務(wù)器發(fā)送請求信息,通信結(jié)束后中斷與客戶的連接。主要的實現(xiàn)步驟為:需要定義運行時候需要的參數(shù),同樣利用socket()建立流式套接字,返回套接字號,connect()將套接字與遠(yuǎn)程主機(jī)連接,recv()和send()將套接字上的讀寫數(shù)據(jù)進(jìn)行發(fā)送與接收,close()關(guān)閉套接字,關(guān)閉對話。
c.c
#include
#include
#include
#include #include
#include
#include
#include
#include
#include
#include
#define SIZE 1024
int main(int argc, char *argv[])
{
pid_t pid;
int sockfd,confd;
char buffer[SIZE],buf[SIZE];
struct sockaddr_in server_addr;
struct sockaddr_in client_addr;
struct hostent *host;
short port;
char *name;
//四個參數(shù)
if(argc!=4)
{
fprintf(stderr,"Usage:%s hostname an",argv[0]);
exit(1);
}
//使用hostname查詢host 名字
if((host=gethostbyname(argv[1]))==NULL)
{
fprintf(stderr,"Gethostname errorn");
exit(1);
}
port=atoi(argv[2]);
name=argv[3];
/*客戶程序開始建立 sockfd描述符 */
if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1)
{
fprintf(stderr,"Socket Error:%san",strerror(errno));
exit(1);
} else{
printf("Socket successful!n");
}
/*客戶程序填充服務(wù)端的資料 */
bzero(&server_addr,sizeof(server_addr)); // 初始化,置0
server_addr.sin_family=AF_INET; // IPV4
server_addr.sin_port=htons(port); // (將本機(jī)器上的short數(shù)據(jù)轉(zhuǎn)化為網(wǎng)絡(luò)上的short數(shù)據(jù))端口號
server_addr.sin_addr=*((struct in_addr *)host->h_addr); // IP地址
/* 客戶程序發(fā)起連接請求 */
if(confd=connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{
fprintf(stderr,"Connect Error:%san",strerror(errno));
exit(1);
}else{
printf("Connect successful!n");
}
/*將客戶端的名字發(fā)送到服務(wù)器端*/
send(sockfd,name,20,0);
/*創(chuàng)建子進(jìn)程,進(jìn)行讀寫操作*/
pid = fork();//創(chuàng)建子進(jìn)程
while(1)
{
/*父進(jìn)程用于發(fā)送信息*/
if(pid > 0)
{
/*時間函數(shù)*/
struct tm *p;
time(&timep);
p = localtime(&timep);
strftime(buffer, sizeof(buffer), "%Y/%m/%d %H:%M:%S", p);
/*輸出時間和客戶端的名字*/
strcat(buffer," nt昵稱 ->");
strcat(buffer,name);
strcat(buffer,":ntt ");
memset(buf,0,SIZE);
fgets(buf,SIZE,stdin);
/*對客戶端程序進(jìn)行管理*/
if(strncmp("e",buf,1)==0)
{
printf("該客戶端下線...n");
strcat(buffer,"退出聊天室!");
if((send(sockfd,buffer,SIZE,0)) <= 0)
{
perror("error send");
}
close(sockfd);
sockfd = -1;
exit(0);
}else
{
strncat(buffer,buf,strlen(buf)-1);
strcat(buffer,"n");
if((send(sockfd,buffer,SIZE,0)) <= 0)
{
perror("send");
}
}
}
else if(pid == 0)
{
/*子進(jìn)程用于接收信息*/
memset(buffer,0,SIZE);
if(sockfd > 0)
{
if((recv(sockfd,buffer,SIZE,0)) <= 0)
{
close(sockfd);
exit(1);
}
printf("%sn",buffer);
}
}
} close(sockfd);
return 0;
}
s.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include#define PORT 4395
#define SIZE 1024
#define SIZE_SHMADD 2048
#define BACKLOG 3
int sockfd;
int fd[BACKLOG];
int i=0;
/*********套接字描述符*******/
int get_sockfd()
{ struct sockaddr_in server_addr; if((sockfd=socket(AF_INET,SOCK_STREAM,0))==-1) { fprintf(stderr,"Socket error:%sna",strerror(errno)); exit(1); }else{
printf("Socket successful!n"); } /*sockaddr結(jié)構(gòu) */
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(PORT);
/*綁定服務(wù)器的ip和服務(wù)器端口號*/
if(bind(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)
{ fprintf(stderr,"Bind error:%sna",strerror(errno));
exit(1);
} else{printf("Bind successful!n"); }
/* 設(shè)置允許連接的最大客戶端數(shù) */
if(listen(sockfd,BACKLOG)==-1)
{ fprintf(stderr,"Listen error:%sna",strerror(errno)); exit(1); } else{
printf("Listening.....n"); }
return sockfd;
}
/*創(chuàng)建共享存儲區(qū)*/
int shmid_create()
{ int shmid; if((shmid = shmget(IPC_PRIVATE,SIZE_SHMADD,0777)) < 0) { perror("shmid error!"); exit(1); }
Else printf("shmid success!n");
return shmid;
}
int main(int argc, char *argv[]) { char shmadd_buffer[SIZE_SHMADD],buffer[SIZE]; struct sockaddr_in client_addr;
int sin_size;
pid_t ppid,pid; int new_fd;
int shmid;
char *shmadd;
/***********共享內(nèi)存**************/
shmid = shmid_create();
//映射共享內(nèi)存
shmadd = shmat(shmid, 0, 0);
/*****創(chuàng)建套接字描述符***********/
int sockfd = get_sockfd();
/*循環(huán)接收客戶端*/
while(1)
{ /* 服務(wù)器阻塞,直到客戶程序建立連接 */
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)(&client_addr),&sin_size))==-1)
{ fprintf(stderr,"Accept error:%sna",strerror(errno)); exit1); }else{printf("Accept successful!n"); }
fd[i++] = new_fd;
printf("n已連接了客戶端%d : %s:%d n",i , inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
/*把界面發(fā)送給客戶端*/
memset(buffer,0,SIZE);
strcpy(buffer,"n——————————————————Welecom come char ———————————————————————n");
send(new_fd,buffer,SIZE,0);
//創(chuàng)建子進(jìn)程客戶端
ppid = fork(); if(ppid == 0)
{
//將加入的新客戶發(fā)送給所有在線的客戶端/
recv(new_fd,buffer,SIZE,0);
strcat( buffer," 進(jìn)入了聊天室....");
for(i=0;i 0)
{
//父進(jìn)程用于接收信息/
memset(buffer,0,SIZE);
if((recv(new_fd,buffer,SIZE,0)) <= 0)
{
close(new_fd);
exit(1); }
memset(shmadd, 0, SIZE_SHMADD);
strncpy(shmadd, buffer, SIZE_SHMADD);//將緩存區(qū)的客戶端信息放入共享內(nèi)存里
printf(" %sn",buffer);
}
if(pid == 0)
{
//子進(jìn)程用于發(fā)送信息/
sleep(1);//先執(zhí)行父進(jìn)程
if(strcmp(shmadd_buffer,shmadd) != 0)
{
strcpy(shmadd_buffer,shmadd);
if(new_fd > 0)
{
if(send(new_fd,shmadd,strlen(shmadd),0) == -1)
{
perror("send");
}
memset(shmadd, 0, SIZE_SHMADD);
strcpy(shmadd,shmadd_buffer);
}
}
}
}
}
} free(buffer);
close(new_fd);
close(sockfd);
return 0;
}
服務(wù)器進(jìn)行編譯執(zhí)行
客戶端進(jìn)行編譯執(zhí)行
服務(wù)器出現(xiàn)結(jié)果
另外打開一個終端執(zhí)行對客戶端代碼編譯執(zhí)行
總結(jié)
以上是生活随笔為你收集整理的linux使用TCP聊天室设计详解,基于linux的TCP网络聊天室设计与实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue双向绑定经典案例
- 下一篇: linux 宽带连接