多路复用IO

#ifndef _MYHEAD_H_
#define _MYHEAD_H_


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/time.h>


//#define FD_SETSIZE 15
#define MYPORT 6667 //1024以下的是保留的端口号,用大于1024的;
#define MYADDR "192.168.1.102"


#endif


//服务器

#include "myhead.h"



int connect_client[MAXSIZE] = {-1};
int clientcnt = 0;


//只用来接受客户端的连接,并且把客户端的文件描述符放置到connect_client数组里面;
void *handle_connect(void *argc)
{
int fd = *((int *)argc);
int i = 0;
int clientfd = 0;

struct sockaddr_in sock_client = {0};
socklen_t len = sizeof(struct sockaddr);

while(1)
{
//1.接收客户端的连接;
clientfd = accept(fd,(struct sockaddr *)&sock_client,&len);
if(clientfd == -1)
{
perror("Server:accept");
return NULL;
}
printf("accept success...client fd = %d\n",clientfd);

//2.当有客户端来连接的时候,将客户端的文件描述符放到数组里面;
//connnet_clinet数组一开始里面的所有元素都是-1;
for(i = 0; i < MAXSIZE; i++)
{
if(connect_client[i] == -1)
{
connect_client[i] = clientfd;
clientcnt++;
break;
}
}
}
return NULL;
}


void *handle_request(void *argc)
{
int fd = *((int *)argc);

/*跟select相关的定义*/
fd_set fdset; //定义了一个集合,就相当于我们在图里面的池子;
int i = 0;
int ret = 0;
int maxfd = -1;
int recvcnt = 0;

struct timeval timeout;
timeout.tv_sec = 10; //10秒;
timeout.tv_usec = 0; //微秒;

char recvbuff[20] = {0};

FD_ZERO(&fdset); //把集合(池子)初始化;

while(1)
{
//1.将客户端的文件描述符放到集合里面进行监视;
for(i = 0; i < MAXSIZE;i++)
{
//如果在handle_connect里面对connect_client数组进行了赋值(也就是将客户端的文件描述符放置到相应的下标中)
//那么在handle_request里面是可以看到的;

if(connect_client[i] != -1)
{
//就是将connect_client[i]文件描述符放到集合fdset里面进行监视;
FD_SET(connect_client[i],&fdset);
if(maxfd < connect_client[i])
{
maxfd = connect_client[i];
}
}
}

//2.用select进行监视;
ret = select(maxfd + 1,&fdset,NULL,NULL,&timeout);
//0代表超时;
if(ret == 0)
{
}
//-1代表有错误发生;
else if(ret == -1)
{
}
else
{
for(i = 0; i < MAXSIZE; i++)
{
if(connect_client[i] != -1)
{
//判断connect_client[i]所对应的文件描述符是否被置位;
if(FD_ISSET(connect_client[i],&fdset))
{
memset(recvbuff,0,sizeof(recvbuff));
recvcnt = recv(connect_client[i],recvbuff,sizeof(recvbuff),0);
if(recvcnt == -1)
{
perror("recv");
}
else if(recvcnt == 0)
{
printf("The client is closed.\n");
connect_client[i] = -1;
close(connect_client[i]); //加上这一个可以避免客户端关闭之后,服务器陷入死循环;
// break;
}
else
{
printf("Recv from Client %d bytes,data:%s\n",recvcnt,recvbuff);
}

if(strcmp(recvbuff,"end") == 0)
{
close(connect_client[i]);
// break;
}
}
}
}
}
}
return NULL;
}
int main()
{
int ret = 0;
int socketfd = 0; //局部变量保存在栈空间,而栈空间是脏的==》里面还是保存的是上一次这个区域里面保存的值;
int clientfd = 0;

struct sockaddr_in sock_server = {0};   //变量类型保存在netinet/in.h里面的;
struct sockaddr_in sock_client = {0}; //保存连接的客户端那边的信息;


/*这行代码很重要!*/
memset(connect_client,-1,sizeof(connect_client));
socklen_t len = sizeof(struct sockaddr);

//第一步:创建套接字;
socketfd = socket(AF_INET,SOCK_STREAM,0);
if(socketfd == -1)
{
perror("socket");
return -1;
}
printf("socket success...\n"); //确保前面的代码是运行正确的;

int opt = 1;


// setsockopt(socketfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));


//第二步:给套接字绑定必要的信息;
sock_server.sin_family = AF_INET; //给服务程序绑定地址族;
sock_server.sin_port = htons(MYPORT); //给服务器程序设定个端口号;
sock_server.sin_addr.s_addr = htonl(INADDR_ANY);//给服务程序绑定IP地址;

ret = bind(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));
if(ret == -1)
{
perror("bind");
return -1;
}
printf("bind success..\n");

ret = listen(socketfd,10);
if(ret == -1)
{
perror("listen");
return -1;
}
printf("listen success...\n");


pthread_t th1 = 0;
pthread_t th2 = 0;

/*创建线程处理客户端连接*/
pthread_create(&th1,NULL,handle_connect,&socketfd);
/*创建线程处理客户端的请求*/
pthread_create(&th2,NULL,handle_request,&socketfd);

pthread_join(th1,NULL);
pthread_join(th2,NULL);

close(socketfd);

return 0;

}


//客户机

#include "myhead.h"


static int socketfd;


void sig_handler(int sigo)
{
close(socketfd);
exit(-1);
}
int main(int argc,char **argv)
{
// int socketfd = 0;
int ret = 0;

struct sockaddr_in sock_server = {0};

if(argc != 2)
{
printf("Please input server addr!\n");
return -1;
}

signal(SIGINT,sig_handler);


socketfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == socketfd)
{
perror("socket");
return -1;
}
printf("socket success...\n");

//用sock_server提醒你们这边连接的是服务器端的IP地址和端口号;
sock_server.sin_family = AF_INET;
sock_server.sin_port = htons(MYPORT);
// sock_server.sin_addr.s_addr = inet_addr(MYADDR);
sock_server.sin_addr.s_addr = inet_addr(argv[1]);
printf("before connect...\n");
ret = connect(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));
printf("after connect...\n");
if(ret == -1)
{
perror("connect");
return -1;
}
printf("Connect success...\n");

char sendbuff[20] = {0};
int sendcnt = 0;

while(1)
{
//第一步:提示客户输入要发送的数据;
printf("Please input a string:\n");
scanf("%s",sendbuff);

//第二步:调用send向套接字发送数据;
// sendcnt = send(socketfd,sendbuff,strlen(sendbuff),0);
sendcnt = write(socketfd,sendbuff,strlen(sendbuff));
if(sendcnt == -1)
{
perror("send");
return -1;
}
else
{
printf("Send to Server %d bytes,data:%s\n",sendcnt,sendbuff);
}
//第三步:判断发送的数据是否是end,如果是,就结束;
if(strcmp(sendbuff,"end") == 0)
{
close(socketfd);
break;
}
}

return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值