C語(yǔ)言實(shí)現(xiàn)簡(jiǎn)易網(wǎng)絡(luò)聊天室
本文實(shí)例為大家分享了C語(yǔ)言實(shí)現(xiàn)網(wǎng)絡(luò)聊天室的具體代碼,供大家參考,具體內(nèi)容如下
業(yè)務(wù)邏輯:
1、客戶(hù)端注冊(cè)名字
2、告訴所有在線(xiàn)的客戶(hù)端,XXX進(jìn)入聊天室
3、新建一個(gè)線(xiàn)程為該客戶(hù)端服務(wù),隨時(shí)接收客戶(hù)端發(fā)送來(lái)的消息
4、當(dāng)接收到一個(gè)客戶(hù)端的消息時(shí),向每一個(gè)客戶(hù)端轉(zhuǎn)發(fā)一份(群聊)
5、同時(shí)在線(xiàn)人數(shù)最多50人
任何客戶(hù)端可以隨意隨時(shí)進(jìn)入或退出客戶(hù)端
服務(wù)端代碼server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef DEBUG
#define debug(format,...) {}
#else
#define debug(format,...) \
{\
fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
fprintf(stdout,format,##__VA_ARGS__);\
fprintf(stdout,"\n");\
}
#endif//DEBUG
#define error(format,...)\
{\
fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
fprintf(stdout,format,##__VA_ARGS__);\
fprintf(stdout,":%m\n");\
exit(EXIT_FAILURE);\
}
// 客戶(hù)端最大連接數(shù)
#define CLIENT_MAX 50
// 服務(wù)器端口號(hào)
#define PORT 5566
// 緩沖區(qū)大小
#define BUF_SIZE 4096
// 重定義socket地址類(lèi)型
typedef struct sockaddr* SP;
// 客戶(hù)端結(jié)構(gòu)體
typedef struct Client
{
int sock;//socket 標(biāo)識(shí)符
pthread_t tid; //線(xiàn)程ID
char name[20];
struct sockaddr_in addr;
}Client;
// 定義50個(gè)存儲(chǔ)客戶(hù)端的結(jié)構(gòu)變量
Client clients[50];
// 定義信號(hào)量用于限制客戶(hù)端的數(shù)量
sem_t sem;
// 信號(hào)處理函數(shù)
void sigint(int num)
{
for(int i=0; i<10; i++)
{
if(clients[i].sock)
{
pthread_cancel(clients[i].tid);//銷(xiāo)毀線(xiàn)程
}
}
debug("服務(wù)器退出!");
exit(EXIT_SUCCESS);
}
void client_eixt(Client* client)
{
sem_post(&sem);
close(client->sock);
client->sock = 0;
}
void client_send(Client* client,char* buf)
{
size_t len = strlen(buf)+1;
for(int i=0; i<CLIENT_MAX; i++)
{
if(clients[i].sock && clients[i].sock != client->sock)
{
send(clients[i].sock,buf,len,0);
}
}
}
void* run(void* arg)
{
Client* client = arg;
char buf[BUF_SIZE] = {};
// 接收昵稱(chēng)
int ret_size = recv(client->sock,client->name,20,0);
if(0 >= ret_size)
{
client_eixt(client);
return NULL;
}
// 通知其它客戶(hù)端新人上線(xiàn)
sprintf(buf,"!!!歡迎%s進(jìn)入聊天室!!!",client->name);
client_send(client,buf);
for(;;)
{
// 接收消息
ret_size = recv(client->sock,buf,BUF_SIZE,0);
if(0 >= ret_size || 0 == strcmp("quit",buf))
{
// 通知其它客戶(hù)端退出
sprintf(buf,"!!!%s退出聊天室!!!",client->name);
client_send(client,buf);
client_eixt(client);
return NULL;
}
strcat(buf,":");
strcat(buf,client->name);
client_send(client,buf);
debug(buf);
}
}
int main(int argc,const char* argv[])
{
signal(SIGINT,sigint);
debug("注冊(cè)信號(hào)處理函數(shù)成功!");
sem_init(&sem,0,CLIENT_MAX);
debug("初始化信號(hào)量成功!");
int svr_sock = socket(AF_INET,SOCK_STREAM,0);
if(0 > svr_sock)
{
error("socket");
}
debug("創(chuàng)建socket對(duì)象成功!");
struct sockaddr_in svr_addr = {};
svr_addr.sin_family = AF_INET;
svr_addr.sin_port = htons(PORT);
svr_addr.sin_addr.s_addr = INADDR_ANY;
socklen_t addrlen = sizeof(svr_addr);
debug("準(zhǔn)備通信地址成功!");
if(bind(svr_sock,(SP)&svr_addr,addrlen))
{
error("bind");
}
debug("綁定socket對(duì)象和通信地址成功!");
if(listen(svr_sock,10))
{
error("listen");
}
debug("設(shè)置監(jiān)聽(tīng)socket監(jiān)聽(tīng)成功!");
for(;;)
{
debug("等待客戶(hù)端連接...");
sem_wait(&sem);
int index = 0;
while(clients[index].sock)
{
index++;
}
clients[index].sock = accept(svr_sock,(SP)&clients[index].addr,&addrlen);
if(0 > clients[index].sock)
{
kill(getpid(),SIGINT);
}
debug("有新的客戶(hù)端連接,from ip:%s",inet_ntoa(clients[index].addr.sin_addr));
pthread_create(&clients[index].tid,NULL,run,&clients[index]);
}
}
客戶(hù)端代碼client.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <semaphore.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef DEBUG
#define debug(format,...) {}
#else
#define debug(format,...) \
{\
fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
fprintf(stdout,format,##__VA_ARGS__);\
fprintf(stdout,"\n");\
}
#endif//DEBUG
#define error(format,...)\
{\
fprintf(stdout,"%s:%d:%s ",__func__,__LINE__,__TIME__);\
fprintf(stdout,format,##__VA_ARGS__);\
fprintf(stdout,":%m\n");\
exit(EXIT_FAILURE);\
}
#define BUF_SIZE 4096
#define SERVER_PORT 5566
#define SERVER_IP "192.168.0.125"
typedef struct sockaddr* SP;
void* run(void* arg)
{
int cli_sock = *(int*)arg;
char buf[BUF_SIZE] = {};
for(;;)
{
int ret_size = recv(cli_sock,buf,BUF_SIZE,0);
if(0 >= ret_size)
{
printf("服務(wù)器正在升級(jí),請(qǐng)稍候登錄!\n");
exit(EXIT_SUCCESS);
}
printf("\r%30s\n>>>",buf);
fflush(stdout);
}
}
int main(int argc,const char* argv[])
{
int cli_sock = socket(AF_INET,SOCK_STREAM,0);
if(0 > cli_sock)
{
error("socket");
}
struct sockaddr_in cli_addr = {};
cli_addr.sin_family = AF_INET;
cli_addr.sin_port = htons(SERVER_PORT);
cli_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
socklen_t addrlen = sizeof(cli_addr);
if(connect(cli_sock,(SP)&cli_addr,addrlen))
{
printf("服務(wù)器正在升級(jí),請(qǐng)稍候登錄!\n");
return EXIT_SUCCESS;
}
char buf[BUF_SIZE] = {};
printf("請(qǐng)輸入你的眤稱(chēng):");
gets(buf);
send(cli_sock,buf,strlen(buf)+1,0);
pthread_t tid;
pthread_create(&tid,NULL,run,&cli_sock);
for(;;)
{
printf(">>>");
gets(buf);
send(cli_sock,buf,strlen(buf)+1,0);
if(0 == strcmp("quit",buf))
{
printf("退出聊天室!\n");
return EXIT_SUCCESS;
}
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C語(yǔ)言字符串函數(shù)操作(strlen,strcpy,strcat,strcmp)詳解
大家好,本篇文章主要講的是C語(yǔ)言字符串函數(shù)操作(strlen,strcpy,strcat,strcmp)詳解,感興趣的同學(xué)趕快來(lái)看一看吧2021-12-12
C語(yǔ)言實(shí)現(xiàn)隨機(jī)發(fā)撲克牌
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)隨機(jī)發(fā)撲克牌,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-04-04
利用C++實(shí)現(xiàn)簡(jiǎn)易的狼人殺游戲
狼人殺游戲是一款非常有趣的角色扮演游戲,它需要玩家之間互相猜測(cè)身份并進(jìn)行投票,通過(guò)推理來(lái)找出真正的狼人。本文將用C++實(shí)現(xiàn)這一游戲,感興趣的可以了解一下2023-04-04
QT 實(shí)現(xiàn)隨機(jī)驗(yàn)證碼功能
本文介紹了如何使用QT技術(shù)實(shí)現(xiàn)一個(gè)具有動(dòng)態(tài)效果的隨機(jī)驗(yàn)證碼系統(tǒng),詳述了CaptchaMovableLabel和CaptchaLabel兩個(gè)自定義類(lèi)的功能,包括顯示和拖動(dòng)字母、繪制噪音點(diǎn)和線(xiàn)條、以及隨機(jī)生成字母等,講解了如何通過(guò)繼承QWidget和QLabel來(lái)實(shí)現(xiàn)這些功能,并通過(guò)MainWindow創(chuàng)建界面2024-10-10
C++實(shí)現(xiàn)四則混合運(yùn)算計(jì)算器
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)四則混合運(yùn)算計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
tc編譯的dos程序和vc編譯的win32控制臺(tái)程序的異同
tc編譯的dos程序和vc編譯的win32控制臺(tái)程序的異同...2007-08-08

