Linux下实现聊天室

介绍:程序在CentOS下,采用C语言实现,结构为Client/Server结构;

服务端程序通过共享存储区存储聊天数据,并发送给每个连接的客户端;

服务端程序和客户端程序都是通过父子进程分别负责发送和接收数据的,避免数据冲撞;

按以下格式调用客户端程序:client.exe 服务端主机IP 端口号(本程序设定为:3490) 用户名(在聊天室中显示的用户名)。

代码如下:

//--------------------------------server.c--------------------------------------------------
//包含工程所需的头文件
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h> //数据类型定义
#include<sys/stat.h>
#include<netinet/in.h> //定义数据结构sockaddr_in
#include<sys/socket.h> //提供socket函数及数据结构
#include<string.h>
#include<unistd.h>
#include<signal.h>
#include<sys/ipc.h>
#include<errno.h>
#include<sys/shm.h>
#include<time.h>
#define PERM S_IRUSR|S_IWUSR
#define MYPORT 3490 //宏定义定义通信端口
#define BACKLOG 10 //宏定义,定义服务程序可以连接的最大客户数量
#define WELCOME "|----------Welcome to the chat room! ----------|" //宏定义,当客户端连接服务端时,想客户发送此欢迎字符串
//转换函数,将int类型转换成char *类型
void itoa(int i,char*string)
{
int power,j;
j=i;
for(power=;j>=;j/=)
power*=;
for(;power>;power/=)
{
*string++=''+i/power;
i%=power;
}
*string='\0';
} //得到当前系统时间
void get_cur_time(char * time_str)
{
time_t timep;
struct tm *p_curtime;
char *time_tmp;
time_tmp=(char *)malloc();
memset(time_tmp,,); memset(time_str,,);
time(&timep);
p_curtime = localtime(&timep);
strcat(time_str," (");
itoa(p_curtime->tm_hour,time_tmp);
strcat(time_str,time_tmp);
strcat(time_str,":");
itoa(p_curtime->tm_min,time_tmp);
strcat(time_str,time_tmp);
strcat(time_str,":");
itoa(p_curtime->tm_sec,time_tmp);
strcat(time_str,time_tmp);
strcat(time_str,")");
free(time_tmp);
}
//创建共享存储区
key_t shm_create()
{
key_t shmid;
//shmid = shmget(IPC_PRIVATE,1024,PERM);
if((shmid = shmget(IPC_PRIVATE,,PERM)) == -)
{
fprintf(stderr,"Create Share Memory Error:%s\n\a",strerror(errno));
exit();
}
return shmid;
}
//端口绑定函数,创建套接字,并绑定到指定端口
int bindPort(unsigned short int port)
{
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(AF_INET,SOCK_STREAM,);//创建基于流套接字
my_addr.sin_family = AF_INET;//IPv4协议族
my_addr.sin_port = htons(port);//端口转换
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),); if(bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr)) == -)
{
perror("bind");
exit();
}
printf("bing success!\n");
return sockfd;
}
int main(int argc, char *argv[])
{
int sockfd,clientfd,sin_size,recvbytes; //定义监听套接字、客户套接字
pid_t pid,ppid; //定义父子线程标记变量
char *buf, *r_addr, *w_addr, *temp, *time_str;//="\0"; //定义临时存储区
struct sockaddr_in their_addr; //定义地址结构
key_t shmid; shmid = shm_create(); //创建共享存储区 temp = (char *)malloc();
time_str=(char *)malloc();
sockfd = bindPort(MYPORT);//绑定端口
while()
{
if(listen(sockfd,BACKLOG) == -)//在指定端口上监听
{
perror("listen");
exit();
}
printf("listening......\n");
if((clientfd = accept(sockfd,(struct sockaddr*)&their_addr,&sin_size)) == -)//接收客户端连接
{
perror("accept");
exit();
}
printf("accept from:%d\n",inet_ntoa(their_addr.sin_addr));
send(clientfd,WELCOME,strlen(WELCOME),);//发送问候信息
buf = (char *)malloc(); ppid = fork();//创建子进程
if(ppid == )
{
//printf("ppid=0\n");
pid = fork(); //创建子进程
while()
{
if(pid > )
{
//父进程用于接收信息
memset(buf,,);
//printf("recv\n");
//sleep(1);
if((recvbytes = recv(clientfd,buf,,)) <= )
{
perror("recv1");
close(clientfd);
raise(SIGKILL);
exit();
}
//write buf's data to share memory
w_addr = shmat(shmid, , );
memset(w_addr, '\0', );
strncpy(w_addr, buf, );
get_cur_time(time_str);
strcat(buf,time_str);
printf(" %s\n",buf);
}
else if(pid == ) {
//子进程用于发送信息
//scanf("%s",buf);
sleep();
r_addr = shmat(shmid, , );
//printf("---%s\n",r_addr);
//printf("cmp:%d\n",strcmp(temp,r_addr));
if(strcmp(temp,r_addr) != )
{
strcpy(temp,r_addr);
get_cur_time(time_str);
strcat(r_addr,time_str);
//printf("discriptor:%d\n",clientfd);
//if(send(clientfd,buf,strlen(buf),0) == -1)
if(send(clientfd,r_addr,strlen(r_addr),) == -)
{
perror("send");
}
memset(r_addr, '\0', );
strcpy(r_addr,temp);
}
}
else
perror("fork");
}
}
}
printf("------------------------------\n");
free(buf);
close(sockfd);
close(clientfd);
return ;
} //-----------------------------client.c-------------------------------------------------
//包含工程所需的头文件
#include<stdio.h>
#include<netinet/in.h> //定义数据结构sockaddr_in
#include<sys/socket.h> //提供socket函数及数据结构
#include<sys/types.h> //数据类型定义
#include<string.h>
#include<stdlib.h>
#include<netdb.h>
#include<unistd.h>
#include<signal.h>
#include<time.h>
int main(int argc, char *argv[])
{
struct sockaddr_in clientaddr;//定义地址结构
pid_t pid;
int clientfd,sendbytes,recvbytes;//定义客户端套接字
struct hostent *host;
char *buf,*buf_r;
if(argc < )
{
printf("usage:\n");
printf("%s host port name\n",argv[]);
exit();
}
host = gethostbyname(argv[]);
if((clientfd = socket(AF_INET,SOCK_STREAM,)) == -) //创建客户端套接字
{
perror("socket\n");
exit();
}
//绑定客户端套接字
clientaddr.sin_family = AF_INET;
clientaddr.sin_port = htons((uint16_t)atoi(argv[]));
clientaddr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(clientaddr.sin_zero),);
if(connect(clientfd,(struct sockaddr *)&clientaddr,sizeof(struct sockaddr)) == -) //连接服务端
{
perror("connect\n");
exit();
}
buf=(char *)malloc();
memset(buf,,);
buf_r=(char *)malloc(); if( recv(clientfd,buf,,) == -)
{
perror("recv:");
exit();
}
printf("\n%s\n",buf); pid = fork();//创建子进程
while()
{
if(pid > ){
//父进程用于发送信息 //get_cur_time(time_str); strcpy(buf,argv[]);
strcat(buf,":");
memset(buf_r,,);
//gets(buf_r);
fgets(buf_r,,stdin);
strncat(buf,buf_r,strlen(buf_r)-);
//strcat(buf,time_str);
//printf("---%s\n",buf);
if((sendbytes = send(clientfd,buf,strlen(buf),)) == -)
{
perror("send\n");
exit();
}
}
else if(pid == )
{
//子进程用于接收信息
memset(buf,,);
if(recv(clientfd,buf,,) <= )
{
perror("recv:");
close(clientfd);
raise(SIGSTOP);
exit();
}
printf("%s\n",buf);
}
else
perror("fork");
}
close(clientfd);
return ;
}

Linux C 简易聊天室的更多相关文章

  1. php+websocket搭建简易聊天室实践

    1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短 ...

  2. Socket实现简易聊天室,Client,Server

    package seday08; import java.io.BufferedWriter;import java.io.OutputStream;import java.io.OutputStre ...

  3. node.js+websocket实现简易聊天室

    (文章是从我的个人主页上粘贴过来的,大家也可以访问我的主页 www.iwangzheng.com) websocket提供了一种全双工客户端服务器的异步通信方法,这种通信方法使用ws或者wss协议,可 ...

  4. php_D3_“简易聊天室 ”实现的关键技术 详解

                      PHP+MySQL实现Internet上一个简易聊天室的关键技术  系统目标: 聊天室使用数据库汇集每个人的发言,并可将数据库内的发言信息显示在页面,让每个用户都可 ...

  5. Python开发【笔记】:aiohttp搭建简易聊天室

    简易聊天室: 1.入口main.py import logging import jinja2 import aiohttp_jinja2 from aiohttp import web from a ...

  6. 学习JavaSE TCP/IP协议与搭建简易聊天室

    一.TCP/IP协议 1.TCP/IP协议包括TCP.IP和UDP等 2.域名通过dns服务器转换为IP地址 3.局域网可以通过IP或者主机地址寻找到相应的主机 4.TCP是可靠的连接,效率低,且连接 ...

  7. 示例:Socket应用之简易聊天室

    在实际应用中,Server总是在指定的端口上监听是否有Client请求,一旦监听到Client请求,Server就会启动一个线程来响应该请求,而Server本身在启动完线程之后马上又进入监听状态. 示 ...

  8. node+websocket创建简易聊天室

    关于websocket的介绍太多,在这就不一一介绍了,本文主要实现通过websocket创建一个简易聊天室,就是90年代那种聊天室 服务端 1.安装ws模块,uuid模块,ws是websocket模块 ...

  9. 基于Node.js + WebSocket 的简易聊天室

    代码地址如下:http://www.demodashi.com/demo/13282.html Node.js聊天室运行说明 Node.js的本质就是运行在服务端的JavaScript.Node.js ...

随机推荐

  1. 2014年同年CFA考试中哪些CFA资料没有变化?

    从2014年起,美国CFA协会将官方教材.题库.模拟题等CFA资料捆绑在报名费用之中,而以往可以单独选购的纸质版教材也变成了额外购买.这让非常多參加12月的CFA考生产生了借阅6月考生CFA资料的想法 ...

  2. SharePoint 2013 Designer 自己定义操作菜单

    众所周知,我们在SharePoint的二次开发中,常常会加入ECB菜单或者Ribbon菜单,通常我们会採取Feature的方式去加入一个Xml,或者採取JavaScript的方式.当然.除此之外,还能 ...

  3. SQL Server索引进阶:第十三级,插入,更新,删除

    在第十级到十二级中,我们看了索引的内部结构,以及改变结构造成的影响.在本文中,继续查看Insert,update,delete和merge造成的影响.首先,我们单独看一下这四个命令. 插入INSERT ...

  4. switch_case,&&,||,条件操作符和逗号操作符,循环语句

    一.switch-case switch-case语句主要用在多分支条件的环境中,在这种环境中使用if语句会存在烦琐且效率不高的弊端. switch(expression) { case const ...

  5. USACO Section 4.2 The Perfect Stall(二分图匹配)

    二分图的最大匹配.我是用最大流求解.加个源点s和汇点t:s和每只cow.每个stall和t 连一条容量为1有向边,每只cow和stall(that the cow is willing to prod ...

  6. 在zendstudio上配置SVN

    本文介绍zendstudio结合SVN的使用方法. 一.部署svn服务器 直接安装用svn软件,配置太过麻烦,用户和版本库.权限管理不太方便.推荐使用CollabNetSubversionEdge.以 ...

  7. Jquery 获取IP地址

    //获取ip和地址 $(function () { var url = 'http://chaxun.1616.net/s.php?type=ip&output=json&callba ...

  8. python之面向对象那点事

    一.类与对象 1.什么是类?类,顾名思义,就是具体相同属性的同一类事物的统称及抽象.对象,指是就是具体的抽象类的实例 以上的说法是不是看起来有点云里来雾里去呢.没错,专业的解释总是让人难以理解,这就是 ...

  9. python 之日期时间处理

    ##python时间操作一般使用time.datetime两个模块 对于time模块,时间的表示模式有3种1.时间戳:time.time()2.字符串: time.strftime('%Y%m%d') ...

  10. WireShark抓包时TCP数据包出现may be caused by ip checksum offload

    最近用WireShark抓包时发现TCP数据包有报错:IP Checksum Offload,经过查阅资料终于找到了原因 总结下来就是wireshark抓到的数据包提示Checksum错误,是因为它截 ...