1.聊天室程序——客户端

客户端我也用了select进行I/O复用,同时监控是否有来自socket的消息和标准输入,近似可以完成对键盘的中断使用。

其中select的监控里,STDOUT和STDIN是已有规定的值了。

Socket_setup函数负责进行对socket进行初始化完成connect 的过程,然后在主函数里无限循环检查sockfd和STDIN的缓冲区是否有新的消息

客户端程序较简单:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h> #define BUF_SIZE 256
#define STDIN 0
#define STDOUT 1
#define INVALID -1 int
socket_setup(const char *serv_ip, int serv_port)
{
int rtn,sockfd;
struct sockaddr_in sockaddr; sockfd = socket(AF_INET, SOCK_STREAM, );
bzero(&sockaddr,sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(serv_port);
inet_pton(AF_INET, serv_ip, &sockaddr.sin_addr); rtn = connect(sockfd,(struct sockaddr *)&sockaddr, sizeof(sockaddr)); if (rtn == INVALID)
{
puts("connection failure\n");
exit();
}
else
{
puts("connection successful\n");
return sockfd;
}
} int
main(int argc, const char *argv[])
{
int i,read_size, sockfd = socket_setup(argv[],argv[]);
char buffer[BUF_SIZE];
fd_set fdset; while ()
{
FD_ZERO(&fdset);
FD_SET(STDIN, &fdset);
FD_SET(sockfd, &fdset);
select(sockfd + , &fdset, NULL, NULL, ); if( FD_ISSET( sockfd, &fdset ) )
{
readsize = read(sockfd, buffer, BUF_SIZE);
write(STOUT, buffer, read_size); if(read_size == )
{
puts("server close");
exit();
}
} if(FD_ISSET(STDIN, &fdset))
{
read_size = read(STDIN, buffer, BUF_SIZE);
write(sockfd, buffer, read_size);
}
} return ;
}

2.聊天室程序——服务器端

我的想法是,只要建立一个数组来存放客户端信息,每次有客户端发送信息或者在服务器端有消息需要发出去,直接遍历每一个元素给每个客户端发一个就好,客户端只需要完成以下几件事:

1.初始化,因为select的性质,每次检测完后会清空fdset,所以需要每一次都把所有连接上了客户端都重新加入进fdset,涉及函数void init_clients(void),int main(int argc,const char *argv[]

2.检测有没有新的信息发上来了,如果有,并且可读,那就广播出去,涉及函数:void chat(fd_set fdset),void broadcast(char *msg)

3.把所有发上来的信息按照时间格式化输出,这里学到了几个新函数,一个是int sprintf( char *buffer, const char *format, [ argument] … );可以格式化输出字符串和数字,一个是对世间的格式化,size_t strftime(char *strDest,size_t maxsize,const char *format,const struct tm *timeptr );这里涉及的函数:void stdmsg(int i, char *buffer, const char *msg)

源程序是:

 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <arpa/inet.h> #define TIME_SIZE 16 // 表示时间的字符串长度
#define IP_SIZE 16 // IP 字符串长度
#define BUF_SIZE 256 // 缓冲区大小
#define CLIENT_SIZE 8 // 允许的客户端数量
#define BACKLOG CLIENT_SIZE // listen 队列长度,等于允许的客户端数量
#define INVALID -1 struct CLIENT{
int clienfd;
struct sockaddr_in sockaddr;
char ip[IP_SIZE];
int port;
}clients[CLIENT_SIZE]; void init_clients(void)
{
int i; for( i = ; i < CLIENT_SIZE; i++ )
{
clients[i].clientfd = INVALID;
}
} void broadcast(char *msg)
{
int i; for(i = ; i<CLIENT_SIZE; i++)
{
if( clients[i].clienfd != INVALID )
{
write(clients[i].clientfd, msg, sterlen(msg));
}
}
} void stdmsg(int i, char *buffer, const char *msg)
{
char curtime[TIME_SIZE];
time_t curtime_t;
struct tm *timeinfo; curtime_t = time(NULL);
timeinfo = localtime(&curtime_t);
strftime(curtime, TIME_SIZE, "%X", timeinfo);
sprintf(buffer,"<%s %s:%d> %s",curtime,clients[i].ip,clients[i].port,msg);
} void accept_connect(int listenfd)
{
int connectfd,i;
char buffer[BUF_SIZE];
struct sockaddr_in clientaddr;
socklen_t connectlen = sizeof(struct sockaddr_in); connectfd = accept( listenfd, (struct sockaddr_in *)&clientaddr, &connectlen); for( i = ; i < CLIENT_SIZE, i++ )
{
if(clients[i].clienfd == INVALID)
{
clients[i].clienfd == connectfd;
memcpy(&clients[i].sockaddr);
clients[i].port = ntohs(clients[i].sockaddr.sin_port);
inet_ntop(AF_INET, &clients[i].sockaddr.sin_addr, clients[i].ip, IP_SIZE);
stdmsg(i,buffer,"login\n");
printf("%s",buffer);
broadcast(buffer);
break;
}
} if (i == CLIENT_SIZE )
{
strcpy(buffer, "out of number\n");
write(connectfd, buffer, strlen(buffer));
close(connectfd);//所有操作利用buffer进行操作
}
} void chat(fd_set fdset)
{
int sockfd, read_size, i;
char read_buf[BUF_SIZE], send_buf[BUF_SIZE]; for( i = ; i < CLIENT_SIZE; i++ )
{
sockfd = clients[i].clienfd; if(sockfd != INVALID && FD_ISSET(sockfd,&fdset))
{
read_size = read(sockfd, read_buf, BUF_SIZE - ); if(read_size == )
{
//connection lost
close(sockfd);
clients[i].clienfd = INVALID;
stdmsg(i, send_buf, "logout\n");
printf("%s\n",send_buf);
broadcast(send_buf); continue;
}
else
{
read_buf[read_size] = '\0';
stdmsg(i, send_buf, read_buf);
printf("%s",send_buf);
broadcast(send_buf);
}
}
}
} int socket_setup(int port)
{
int rtn, listenfd = socket(AF_INET, SOCK_STREAM, );
struct sockaddr_in sockaddr; bzero(&sockaddr, sizeof(sockaddr));
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); rtn = bind(listenfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
if (rtn == INVALID)
{
puts("bind error\n");
exit();
} if(listen(listenfd,BACKLOG) == INVALID)
{
puts("listen error\n")
exit();
} puts("service setup\n");
return listenfd;
} int main(int argc,const char *argv[])
{
int maxfd, i, listenfd = socket_setup(atoi(argv[]));
fdset fdset; init_clients(); while()
{
FD_ZERO(&fdset);
FD_SET(listenfd, &fdset);
maxfd = listenfd; for(i = ; i < CLIENT_SIZE; i++)
{
if(clients[i].clienfd != INVALID)
{
FD_SET(clients[i].clienfd, &fdset); if(clients[i].clienfd > maxfd)
{
maxfd = clients[i].clienfd;
}
}
} select(maxfd + , &fdset, NULL, NULL, ); if(FD_ISSET(listenfd, &fdset))
{
accept_connect(listenfd);
}
chat(fdset);
}
return ;
}

用c写一个小的聊天室程序的更多相关文章

  1. 利用JavaUDPSocket+多线程模拟实现一个简单的聊天室程序

    对Socket的一点个人理解:Socket原意是指插座.家家户户都有五花八门的家用电器,但它们共用统一制式的插座.这样做的好处就是将所有家用电器的通电方式统一化,不需要大费周章地在墙壁上凿洞并专门接电 ...

  2. ASP.NET 使用application和session对象写的简单聊天室程序

    ASP.Net中有两个重要的对象,一个是application对象,一个是session对象. Application:记录应用程序参数的对象,该对象用于共享应用程序级信息. Session:记录浏览 ...

  3. 基于websocket实现的一个简单的聊天室

    本文是基于websocket写的一个简单的聊天室的例子,可以实现简单的群聊和私聊.是基于websocket的注解方式编写的.(有一个小的缺陷,如果用户名是中文,会乱码,不知如何处理,如有人知道,请告知 ...

  4. 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室

    原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  5. 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室

    原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...

  6. [SignalR]一个简单的聊天室

    原文:[SignalR]一个简单的聊天室 1.说明 开发环境:Microsoft Visual Studio 2010 以及需要安装NuGet. 2.添加SignalR所需要的类库以及脚本文件: 3. ...

  7. 用ServletContext做一个简单的聊天室

    这里主要是ServletContext的一个特性:ServletContext是一个公共的空间,可以被所有的客户访问.由此可见ServletContext比cookie和session的作用范围要大[ ...

  8. Python之小测试:用正则表达式写一个小爬虫用于保存贴吧里的所有图片

    很简单的两步: 1.获取网页源代码 2.利用正则表达式提取出图片地址 3.下载 #!/usr/bin/python #coding=utf8 import re # 正则表达式 import urll ...

  9. 基于select的python聊天室程序

    python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...

随机推荐

  1. Java线程入门第二篇

    Java线程通信方法 0.(why)每个线程都有自己的栈空间,我们要线程之间进行交流,合作共赢. 1.synchronized和volatile关键字 a)  看下面的synchronized关键字 ...

  2. 【SSH网上商城项目实战14】商城首页UI的设计

    转自:https://blog.csdn.net/eson_15/article/details/51373403 前面我们利用EasyUI和SSH搭建好了后台的基本框架,做好了后台的基本功能,包括对 ...

  3. [APIO2018] Circle selection 选圆圈(假题解)

    题面 自己去\(LOJ\)上找 Sol 直接排序然后\(KDTree\)查询 然后发现\(TLE\)了 然后把点旋转一下,就过了.. # include <bits/stdc++.h> # ...

  4. Web服务器学习总结(一):web服务器简介

    一.WEB服务器 1.1.WEB服务器简介 1.Web服务器是指驻留于因特网上某种类型计算机的程序,是可以向发出请求的浏览器提供文档的程序.当Web浏览器(客户端)连到服务器上并请求文件时,服务器将处 ...

  5. MPU/SoC/Application Processor/Embedded OS

    Everything has its principles and mechanisms which are designed by its creator and followed by its u ...

  6. WinAPI: WinExec - 运行外部程序

    原文:http://www.cnblogs.com/del/archive/2008/02/13/1067871.html //声明 WinExec(   lpCmdLine: LPCSTR; {文件 ...

  7. 用Jmeter进行接口测试及乱码问题

    web接口测试工具: 手工测试的话可以用postman ,自动化测试多是用到 Jmeter(开源).soupUI(开源&商业版). 下面将对前一篇Postman做接口测试中的接口用Jmeter ...

  8. c#微信开发,使用JS-SDK自定义分享功能,分享朋友圈,分享给朋友等

    如果一个后端开发掌握了微信开发,甚至有微信开发上线项目,这在换工作的时候 还是有竞争力的. 微信开发的资料很多,但是用asp.net c#进行微信开发好像比较少,或者资料不够完整. 使用JS-SDK自 ...

  9. 入门级 - 码云(Gitee),GitHub 教程

    这篇文章的目的是记录我的关于GitHub的内容,从注册.下载直到设置成功每一步都有解释,其中有一些截图或者代码来自于网络. GitHub和码云均基于Git,所以两者的操作方法基本一致,只需要学习其中一 ...

  10. Shell脚本例子集合

    # vi xx.sh 退出并保存 # chmod +x xx.sh # ./xx.sh -2. 调试脚本的方法 # bash -x xx.sh 就可以调试了 . -1. 配置 secureCRT 的设 ...