tcp 多路复用实现 两个客户端之间的通信

/*******************************

服务器端 

****************************/

#include <stdio.h>

#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>


#define BACKLOG 5






int main(int argc, char** argv){


if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);




int listenfd;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("listen error\n");
}


struct sockaddr_in srvaddr;
    bzero(&srvaddr,sizeof(srvaddr));
  srvaddr.sin_family = AF_INET;
  srvaddr.sin_port = htons(PORT);
  srvaddr.sin_addr.s_addr = htonl(INADDR_ANY);

  int on = 1;
  if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
  {
  printf("set sock error");
  }


if(bind(listenfd, (struct sockaddr *) &srvaddr, sizeof(srvaddr)) < 0)
{
printf("bind error\n");
close(listenfd);
exit(1);
}


if(listen(listenfd, BACKLOG) < 0)
{
printf("listen error\n");
}


struct sockaddr_in peeraddr;
socklen_t peerlen;
int conn;






int i; 
int client[FD_SETSIZE];
for(i = 0; i < FD_SETSIZE; i++){
client[i] = -1;
}
///
int nready;
int maxfd = listenfd; 


fd_set rset;
fd_set aset;


FD_ZERO(&rset);
FD_ZERO(&aset);


FD_SET(listenfd, &aset);


while(1)
{
rset = aset;
nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
/*功能:检查多个文件描述符(socket描述符)是否就绪,当某一个描述符就绪(可读、可写或发生异常)时函数返回,可以实现输入输出多路复用
返回值:有描述符就绪则返回就绪的描述符个数;超时时间内没有描述符就绪返回0;执行失败返回 -1
*/
if (nready == -1)
{
if(errno == EINTR){
continue;
}
printf("select error\n");
}


if (nready == 0)///描述符就绪
{
continue;
}


int conn1;


if(FD_ISSET(listenfd, &rset)) {//如果描述符就绪
peerlen = sizeof(peeraddr);
if((conn = accept(listenfd, (struct sockaddr*) &peeraddr, &peerlen)) < 0)//如果监听端口就绪 来一个用户监听一个用户 并把返回的值给conn
{
printf("accept error");//接收失败
}
    FD_SET(conn, &aset);
for(i = 0; i <FD_SETSIZE; i++)//每来一个用户fd_setsize -1
{
if(client[i] < 0)
{
client[i] = conn;
if( i > maxfd)
maxfd = i;
break;
}
}


if(i == FD_SETSIZE)
{
fprintf(stderr, "too many clients\n");
exit(EXIT_FAILURE);
}


printf("received from client by accept: %s, %d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));


if(conn > maxfd)
maxfd = conn;


if(--nready <= 0)
continue;
}








char recvbuf[1024];
char sendbuf[1024];
for(i = 0 ; i < maxfd ; i++){
conn = client[i];

conn1 = client[i+1];

/*********************************

文件描述符相当与指针 指向不同客户端

检查文件描述符conn是否可以准备 如果是

从文件描述符conn发送到conn1 实现conn向conn1发送信息

如果不是 看conn1是否就绪 如果是

从文件描述符conn1发送到conn 实现conn1向conn发送信息

*********************************/

if(FD_ISSET(conn, &rset) )
{




memset(recvbuf, 0, sizeof(recvbuf));


int ret = read(conn, recvbuf, 1024);

if(ret == -1) {
printf("read error");
break;



if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}

fputs(recvbuf, stdout);
write(conn1, recvbuf, strlen(recvbuf));


if(-- nready <=0 )
{
break;
}
}


if(FD_ISSET(conn1, &rset) )
{




memset(recvbuf, 0, sizeof(recvbuf));


int ret = read(conn1, recvbuf, 1024);

if(ret == -1) {
printf("read error");
break;



if(ret == 0)
{
printf("client close\n");
FD_CLR(conn, &aset);
client[i] = -1;
break;
}

fputs(recvbuf, stdout);
write(conn, recvbuf, strlen(recvbuf));


if(-- nready <=0 )
{
break;
}
}


   }
}

}

/*********************************

客户端

******************************/

#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <strings.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <signal.h>
//这个函数就是用来发送信息到服务器
void echo_cli(int sock)
{




fd_set rset;
FD_ZERO(&rset);


// jiancedao shijian geshu
int nready;


int fd_stdin = fileno(stdin);
int maxfd;


if(fd_stdin > sock)
{
maxfd = fd_stdin;
} else
{
maxfd = sock;
}


char sendbuf[1024]= {0};
char recvbuf[1024]= {0};


while(1){


FD_SET(fd_stdin, &rset);
FD_SET(sock, &rset);


nready = select(maxfd + 1, &rset, NULL, NULL, NULL);
if(nready == -1)
{
printf("select error");

if(nready == 0)
{
continue;
}


if(FD_ISSET(sock, &rset)){
int ret = read(sock, recvbuf, sizeof(recvbuf));


if(ret == 0 )
{
printf("server close\n");
break;
}

fputs(recvbuf, stdout);
memset(recvbuf, 0, sizeof(recvbuf));
}
if(FD_ISSET(fd_stdin, &rset)){
if(fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)
break;
write(sock,sendbuf,strlen(sendbuf));
}
}


close(sock);
}


int main(int argc, char** argv){


if(argc != 2){
fprintf(stderr, "Usage: %s [portnumber]\n", argv[0]);
exit(1);
}
int PORT = atoi(argv[1]);


int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);


struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

if(connect(sock, (struct sockaddr*) &servaddr, sizeof(servaddr)) < 0)
{
printf("connect error\n");
close(sock);
exit(1);
}


echo_cli(sock);


}












猜你喜欢

转载自blog.csdn.net/qq_37126193/article/details/78436295
今日推荐