使用epoll来做为两个client socket的中转站
问题描述
我建立一个socket server, 当有其他client连接时,如果一开始输入key123, 那么就认为它是主client, 监视它的in和out, 如果连接后输入的不是key123, 那么就是从client, 从client可以有多个
从client输入的字符都会被server转发到主client, 主client输入的字符会被群发到所有从client
如果telnet 127.0.0.1 2323这样的手工方法,没有问题,
但如果我用C写个程序来模拟手工输入,那么主client很快后读失败,而且server的状态不如预期
问题出现的环境背景及自己尝试过哪些方法
我尝试过用nonblocking,也不行
相关代码
// 请把代码文本粘贴到下方(请勿用图片代替代码)
socket server
static void handle_accept(int epollfd, int listenfd, cli_t * pclient)
{
int clifd;
struct sockaddr_in cliaddr;
pclient->cliaddr = &cliaddr;
socklen_t cliaddrlen = sizeof(*(pclient->cliaddr));
clifd = accept(listenfd,(sockaddr*)(pclient->cliaddr),&cliaddrlen);
if (clifd == -1)
{
if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) ) {
return;
} else {
perror("accpet error:");
}
} else {
report_peer_connected((pclient->cliaddr), cliaddrlen);
set_socket_non_blocking(clifd);
add_event(epollfd,clifd,EPOLLIN|EPOLLOUT);
// add one client read event
int nread, nwrite;
#if 0
const char * req = "please input the key:\n";
printf("size: %d\n", sizeof(req));
while ((nwrite = write(clifd,req,strlen(req)))<0)
{
if(nwrite == -1){
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
//sleep(1);
continue;
} else {
perror("read error");
exit(1);
}
}
}
#endif
int times=0;
// sleep(3);
memset(ibuf, 0, sizeof(buf_t));
//while (((nread = read(clifd,ibuf->buf,MAXSIZE))<0) && (times < 100))
while (((nread = read(clifd,ibuf->buf,MAXSIZE))<0))
{
if(nread == -1){
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
// usleep(100000);
times++;
continue;
} else {
perror("read error");
exit(1);
}
}
}
if (nread == 0) {
fprintf(stderr, "nread: the client closed\n");
} else {
printf("nread: %d, ibuf->buf: %s\n", nread, ibuf->buf);
if((strncmp(ibuf->buf , "key123", 6) == 0))
{
#ifdef DEBUG
printf("get HW connection\n");
#endif
pclient->hwfd = clifd;
pclient->hwcon = 1;
} else {
#ifdef DEBUG
printf("get SW connection\n");
#endif
pclient->swfd.push_back(clifd);
(pclient->swconnum)++;
delete_event(epollfd,clifd,EPOLLIN);
}
}
}
}
// HW side reads message from the client
static void do_read(int epollfd, int fd, cli_t * pclient)
{
if((fd == pclient->hwfd)) //if it's hw side
{
memset(ibuf, 0, sizeof(buf_t));
int nread;
nread = read(fd,ibuf->buf,MAXSIZE);
if (nread == -1)
{
perror("read error:");
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else if (nread == 0)
{
fprintf(stderr,"client %s:%d close.\n", inet_ntoa(pclient->cliaddr->sin_addr), ntohs(pclient->cliaddr->sin_port));
close(fd);
delete_event(epollfd,fd,EPOLLIN);
}
else
{
// get message from HW side
{
#ifdef DEBUG
printf("read message from hw is : %s\n",ibuf->buf);
#endif
}
int nwrite;
for(int i=0; i<(pclient->swconnum);i++)
{
nwrite = write((pclient->swfd[i]),ibuf->buf,nread);
}
//modify_event(epollfd,fd,EPOLLIN|EPOLLOUT);
}
}
}
// HW side writes message to the client
static void do_write(int epollfd,int fd, cli_t * pclient)
{
if((fd == pclient->hwfd)) //if it's hw side
{
int nwrite;
int nread;
char towrite[MAXSIZE];
for(int i=0;i<((pclient->swfd).size());i++)
{
set_socket_non_blocking((pclient->swfd[i]));
nread=read((pclient->swfd[i]), obuf->buf, MAXSIZE);
if((nread == -1) && ((errno == EAGAIN || errno == EWOULDBLOCK)))
{
} else {
if(nread == -1)
{
perror("read error:");
pclient->swfd.erase((pclient->swfd).begin()+i);
pclient->swconnum--;
} else {
if(nread == 0)
{
fprintf(stderr, "client closed.\n");
close(pclient->swfd[i]);
pclient->swfd.erase((pclient->swfd).begin()+i);
pclient->swconnum--;
} else {
#ifdef DEBUG
printf("write message to hw is : %s\n", obuf->buf);
#endif
nwrite=write(fd, obuf->buf, nread);
}
}
}
}
//modify_event(epollfd,fd,EPOLLIN);
}
}
static void handle_events(int epollfd, int listenfd, struct epoll_event * events, int num, cli_t* pclient, TRANSTATE * ts )
{
int i;
int fd;
struct sockaddr_in cliaddr;
//*ts = INIT;
// wark over the event ready
for (i = 0;i < num;i++)
{
fd = events[i].data.fd;
// deal as to different event
if ((fd == listenfd) &&(events[i].events & EPOLLIN))
{
handle_accept(epollfd, listenfd, pclient);
} else {
if (events[i].events & EPOLLIN)
{
do_read(epollfd, fd, pclient);
} else {
if (events[i].events & EPOLLOUT)
{
do_write(epollfd,fd,pclient);
}
}
}
}
}
static void do_epoll(int listenfd)
{
// int epollfd;
struct epoll_event events[EPOLLEVENTS];
cli_t * pclient = (cli_t*)malloc(sizeof(cli_t));
set_socket_non_blocking(listenfd);
int ret;
// create one epoll fd
int epollfd = epoll_create(FDSIZE);
TRANSTATE ts=INIT;
// add one listen fd into epoll pool
add_event(epollfd,listenfd,EPOLLIN);
for ( ; ; )
{
// get the event ready
ret = epoll_wait(epollfd,events,EPOLLEVENTS,EPOLL_TIMEOUT);
if(ret <0) {
perror("epoll_wait failed");
exit(1);
} else if (ret == 0) {
fprintf(stderr, "no socket ready for read within %d secs\n", EPOLL_TIMEOUT/1000);
} else {
handle_events(epollfd,listenfd,events,ret,pclient,&ts);
}
}
close(epollfd);
}
master client
char message[BUF_SIZE];
int nread, nwrite;
int times = 0;
const char * key="key123\n";
printf("key len=%d\n", strlen(key));
#if 1
while ((nwrite = write(sock,key,strlen(key)+1))<0)
{
if(nwrite == -1){
if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
//sleep(1);
printf("nwrite: try again!\n");
continue;
} else {
perror("read error");
exit(1);
}
}
}
#endif
// nwrite = write(sock,key,strlen(key)+1);
if (nwrite == 0) {
fprintf(stderr, "nwrite: the client closed\n");
// exit(1);
} else {
printf("HW connected\n");
}
//keep communicating with server
int count = 0;
while(1)
{
sprintf(message, "%d\n", count++);
//Send count
printf("[Send]: %s", message);
if( (nwrite=write(sock, message, strlen(message)+1)) < 0)
{
perror("write failed");
exit(1);
} else {
if( nwrite == 0)
{
printf("nwwrite: no message written to svr\n");
} else {
printf("writen done\n");
}
}
#if 1
//Receive a reply from the server
while( (nread =read(sock, message, BUF_SIZE)) <= 0)
{
if(nread <0)
{
perror("read failed");
exit(1);
} else {
printf("nread: 0\n");
continue;
}
}
printf("[Recv]: %s\n", message);
#endif
usleep(CLIENT_INTERVAL);
}
close(sock);
exit(0);
}
先运行./go
然后在另一个窗口运行./to
你期待的结果是什么?实际看到的错误信息又是什么?
我期待可以看到./to一直运行, 然后它发出去的0, 1, 2, 3... 会被socket server接收到
一旦有其他client (telnet 127.0.0.1 2323, 然后随便输入字符回车), 那么主client的消息会被发到从client, 从client的消息会被发到主client
实际上./to在read的时候就会出错
read failed: Resource temporarily unavailable
而在socket server侧没有收到主client发过来的数字“0”, 而是一个空字符(0)
read message from hw is :
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
read failed的原因是因为异步引起,返回了EAGAIN, 需要对它做特殊处理
read message的原因还没找到