利用select单线程点对点聊天
select的优点与使用方法
select用单线程的方法遍历所有待读写的I/O接口, 当有接口可用时就会返回. select可设置电脑阻塞或非阻塞.
特别注意: 每次select前都要重新初始化集合和相关的时间结构
使用的基本过程:
//创建要读写的集合,所有的读接口放一个集合,所有的写接口放另一个集合
fd_set fileset1;
fd_set fileset2;
//初始化该集合
FD_ZERO(&fileset1);
FD_ZERO(&fileset2);
//向集合中添加要监听的接口
FD_SET(fd1,&fileset1);
FD_SET(fd2,&fileset1);
...
//开始监听
int ret=select(maxfd+1,&fileset1,&fileset2,NULL,NULL);
//返回后开始处理
switch(ret){
case -1:
if(errno == EINTR)
continue;
err_quit("select");
case 0:
printf("time out\n");
continue;
default:
if(FD_ISSET(fd1,&fileset))
do_service1();
if(FD_ISSET(fd2,&fileset))
do_service2();
if(FD_ISSET(...)
break;
}
实例
只写了server端的,client端差不多
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define MAX(a,b) a>b?a:b;
void err_quit(const char *s){
perror(s);
exit(1);
}
void handler(int signo){
printf("program terminated\n");
exit(0);
}
ssize_t readn(int fd,void *buff,size_t count){
char *buffp;
ssize_t nread;
size_t nleft;
buffp=(char *)buff;
nleft=count;
while(nleft > 0){
if((nread = read(fd,buffp,nleft)) < 0){
if(errno == EINTR)
continue;
else
return -1;
}else if(nread == 0)
break;
nleft -= nread;
buffp += nread;
}
return count-nleft;
}
ssize_t writen(int fd,const void *buff,size_t n){
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr=buff;
nleft=n;
while(nleft > 0){
if((nwritten=write(fd,ptr,nleft)) < 0){
if(nwritten < 0 && errno == EINTR)
continue;
else
return -1;
}else if(nwritten == 0)
break;
nleft -= nwritten;
ptr += nwritten;
}
return n-nleft;
}
ssize_t recv_peek(int fd,void *buf,size_t len){
ssize_t ret;
while(1){
ret=recv(fd,buf,len,MSG_PEEK);
if(ret == -1 && errno == EINTR)
continue;
return ret;
}
}
ssize_t readline(int fd,void *buf,size_t maxline){
ssize_t ret;
size_t nread;
size_t nleft;
char *bufp;
bufp=buf;
nleft=maxline;
while(1){
ret=recv_peek(fd,buf,nleft);
if(ret < 0)
return ret;
else if(ret == 0)
return ret;
nread=ret;
int i;
for(i=0;i<nread;i++){
if(bufp[i] == '\n'){
ret=readn(fd,bufp,i+1);
if(ret != i+1)
err_quit("readn");
return ret;
}
}
if(nread > nleft)
err_quit("readn");
nleft -= nread;
ret=readn(fd,bufp,nread);
if(ret != nread)
err_quit("readn");
bufp += nread;
}
return -1;
}
void recv_service(int fd){
char buf[1024]={0};
int ret=readline(fd,buf,sizeof(buf));
if(ret == -1)
err_quit("read");
else if(ret == 0){
printf("peer closed\n");
exit(0);
}
fputs(buf,stdout);
}
void send_service(int fd){
char buf[1024];
if(fgets(buf,sizeof(buf),stdin) != NULL){
writen(fd,buf,strlen(buf));
}
}
int main(int argc,char *argv[]){
int sockfd,connfd;
socklen_t len;
struct sockaddr_in addr,client;
if((sockfd=socket(PF_INET,SOCK_STREAM,0)) < 0)
err_quit("sockfd");
bzero(&addr,sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
addr.sin_port=htons(5566);
int on=1;
if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) <0)
err_quit("setsockopt");
if(bind(sockfd,(struct sockaddr *)&addr,sizeof(addr))<0)
err_quit("bind");
if(listen(sockfd,10)<0)
err_quit("listen");
len=sizeof(client);
connfd=accept(sockfd,(struct sockaddr *)&client,&len);
if(connfd < 0)
err_quit("accept");
struct sockaddr_in peeraddr;
socklen_t lenth=sizeof(peeraddr);
if(getpeername(connfd,(struct sockaddr *)&peeraddr,&lenth) < 0)
err_quit("getpeername");
printf("peer addr=%s,peer port=%d\n",inet_ntoa(peeraddr.sin_addr),ntohs(peeraddr.sin_port));
char buf[1024];
bzero(buf,sizeof(buf));
fd_set fileset;
while(1){
FD_ZERO(&fileset);
FD_SET(STDIN_FILENO,&fileset);
FD_SET(connfd,&fileset);
int maxfd=MAX(STDIN_FILENO,connfd);
int ret=select(maxfd+1,&fileset,NULL,NULL,NULL);
switch(ret){
case -1:
if(errno == EINTR)
continue;
err_quit("select");
case 0:
printf("time out\n");
continue;
default:
if(FD_ISSET(connfd,&fileset))
recv_service(connfd);
if(FD_ISSET(STDIN_FILENO,&fileset))
send_service(connfd);
break;
}
}
exit(0);
}
利用select单线程点对点聊天的更多相关文章
- 利用select实现伪并发的socket
使用socket模块可以实现程序之间的通信,但是server在同一时刻只能和一个客户端进行通信,如果要实现一个server端可以和多个客户端进行通信可以使用 1.多线程 2.多进程 3.select ...
- Activemq mqtt 点对点聊天实现(转载)
我这想到一个点对点聊天的方法,不用没割人都建立一个topic了,思路还是自定义一个分发策略,具体如下: 1. 建立一个topic,所有人都用匹配订阅的方式订阅以该topic为头的topic,例如:所 ...
- Linux 网络编程详解三(p2p点对点聊天)
//p2p点对点聊天多进程版--服务器(信号的使用) #include <stdio.h> #include <stdlib.h> #include <string.h& ...
- sql判断以逗号分隔的字符串中是否包含某个字符串--------MYSQL中利用select查询某字段中包含以逗号分隔的字符串的记录方法
sql判断以逗号分隔的字符串中是否包含某个字符串---------------https://blog.csdn.net/wttykj/article/details/78520933 MYSQL中利 ...
- 老雷socket编程之PHP利用socket扩展实现聊天服务
老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streamssockets socket_create(AF_ ...
- 利用select/poll监听多个设备详解
如果一个应用程序去处理多个设备,例如应用程序读取网路数据,按键,串口,一般能想到的有三种方法: 方法1:串行+阻塞的方式读取:while(1) { read(标准输入);read(网络);}缺点:每当 ...
- java select单线程 服务器
package com.Select; /** *select单线程 服务器 **/ import java.io.IOException; import java.net.InetSocketAdd ...
- 基于select的python聊天室程序
python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...
- 利用scrollintoview方法模拟聊天室收到新消息
这段时间再写一个聊天的功能,基本的原理已经通了,剩下的就是细化功能和实现了.原理通了不代表就能解决了这个问题,今天就遇到了一个小问题,就是在接收到新的消息以后,最新的消息不能显示在消息区域,而是跑到了 ...
随机推荐
- JVM(Java虚拟机)详解(JDK7)
1.Java内存区域 运行时数据区域: Java 虚拟机在执行Java程序时,定义了若干种程序运行期间会使用到的运行时数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁.另外一些则是与线程 ...
- bfs(火星撞地球)
Meteor Shower 链接:https://ac.nowcoder.com/acm/contest/997/I来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 327 ...
- <转载>面试官: 讲讲MySql表设计需要注意什么?
作者:孤独烟 出处: http://rjzheng.cnblogs.com/ 综述 近期由于复习了一下MySQL的内容看到一篇比较好的文章,转载分享一下.大家看完,其实能避开很多坑.而且很多问题,都是 ...
- Codeforces - 1194D - 1-2-K Game - dp
https://codeforc.es/contest/1194/problem/D 打个n=30的表好像看出了规律. 其实假设k==3,那么 sg[0]=0, sg[1]=mex{sg[0]}=1, ...
- Codeforces - 1194B - Yet Another Crosses Problem - 水题
https://codeforc.es/contest/1194/problem/B 好像也没什么思维,就是一个水题,不过蛮有趣的.意思是找缺黑色最少的行列十字.用O(n)的空间预处理掉一维,然后用O ...
- C# 下载PDF文件(http与ftp)
1.下载http模式的pdf文件(以ASP.NET为例,将PDF存在项目的目录下,可以通过http直接打开项目下的pdf文件) #region 调用本地文件使用返回pdfbyte数组 /// < ...
- XMPP即时通讯协议使用(八)——基于订阅发布实现消息流转业务泳道图
- Algorithms4th 1.1.25 欧几里得算法——数学归纳法证明
欧几里得算法的自然语言描述 计算两个非负整数p和q的最大公约数: 若q是0,则最大公约数为p.否则将p除以q得到余数r,p和q的最大公约数即为q和r的最大公约数. 数学归纳法证明 基础步骤: 若q = ...
- PhpStorm中如何使用database工具
环境:ubuntu18.4 mysql5.7 一. 打开database 1.选择View—>Tool Windows—>Database单击打开. 2.新增数据连接 选择 “+”—> ...
- 7.使用dom4j实现增删改查
1.导入dim4j提供的jar包 (1)dom4j,是一个组织,针对xml解析,提供解析器dom4j (2)dom4j不是javase的一部分(jaxp是的) (3)使用dom4j步骤 - 下载并导入 ...