您的位置:首页 > 理论基础 > 计算机网络

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

2017-11-03 15:39 295 查看
/*******************************

服务器端 

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

#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);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp 通信 服务器