2023/4/24

文章展示了如何使用select和poll系统调用来实现TCP服务器和客户端的通信。服务器端利用select进行监听和处理客户端连接,客户端则使用poll进行数据的发送和接收。代码涵盖了socket创建、连接、监听、接受连接、读写操作等关键步骤。
摘要由CSDN通过智能技术生成

1. 将TCP的select服务器重新写一遍(上交)
2. 将TCP的poll客户端写一遍(上交)
3.  将TCP的select客户端写一遍(上交)

select服务器


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<sys/select.h>
#include<sys/time.h>

#define ERR_MSG(msg) do{\
	fprintf(stderr,"Line:%d\n",__LINE__);\
	perror(msg);\
}while(0)

#define IP "192.168.0.153"
#define PORT 7777

int main(int argc, const char *argv[])
{
	int server_fd = socket(AF_INET,SOCK_STREAM,0);
	if(server_fd < 0)
	{
		ERR_MSG("socket");
		return -1;
	}

	int reuse = 1;
	if(setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse)) < 0)
	{
		ERR_MSG("setsockopt");
		return -1;
	}
	printf("端口允许快速重用\n");

	//填充服务器地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(PORT);
	sin.sin_addr.s_addr = inet_addr(IP);

	//绑定
	if(bind(server_fd,(struct sockaddr*)&sin,sizeof(sin)) < 0)
	{
		ERR_MSG("bind");
		return -1;
	}
	printf("bind success __%d__\n",__LINE__);

	if(listen(server_fd, 128) < 0)
	{
		ERR_MSG("listen");
		return -1;
	}
	printf("listen success __%d__\n", __LINE__);

	//创建读集合
	fd_set readfds,tempfds;
	FD_ZERO(&readfds);  //清空

	//添加
	FD_SET(0,&readfds);
	FD_SET(server_fd,&tempfds);

	//存储最大的文件描述符
	int maxfd = server_fd;



	struct sockaddr_in saveCin[1024-4];
	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);
	int newfd = -1;
	char ch[128] = "";
	ssize_t res = 0;
	int ret = 0;

	printf("__%d__\n",__LINE__);
	while(1)
	{
		tempfds = readfds;	
		printf("__%d__\n",__LINE__);
		ret = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		printf("__%d__\n",__LINE__);
		if(ret < 0)
		{
			ERR_MSG("select");
			return -1;
		}
	
		else if(ret == 0)
		{
			printf("Time out......\n");
			break;
		}
		printf("__%d__\n",__LINE__);


		for(int i=0;i<=maxfd;i++)
		{
			if(FD_ISSET(i,&tempfds) == 0)
			{
				continue;
			}

			if(i == 0)
			{
				printf("触发键盘输入事件---->>>>>>>>>>>>");
				fflush(stdout);

				int sndfd;

				res = scanf("%d %s",&sndfd,ch);
				while(getchar() != '\n');

				if(res != 2)
				{
					fprintf(stderr,"请输入正确的格式:fd string\n");
					continue;
				}

				if(sndfd <= server_fd || sndfd >= 1024 || !FD_ISSET(sndfd,&readfds))
				{
					fprintf(stderr,"sndfd = %d 是非法的文件描述符\n",sndfd);
					continue;
				}

				if(send(sndfd,ch,sizeof(ch),0) < 0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("send to %d success\n",sndfd);


			}
			else if(server_fd == i)
			{
				printf("触发客户端事件--->>>>>>");
				fflush(stdout);

				newfd = accept(server_fd,(struct sockaddr*)&cin,&addrlen);
				if(newfd < 0)
				{
					ERR_MSG("accept");
					return -1;
				}
				printf("[%s : %d] newfd = %d 连接成功__%d__\n",\
						inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,__LINE__);
				saveCin[newfd - 4] = cin;

				FD_SET(newfd,&readfds);

				maxfd = maxfd>newfd?maxfd:newfd;
			}

			else
			{
				fprintf(stderr,"触发客户端交互事件>>>>>>>>");
				bzero(ch,sizeof(ch));

				res = recv(i,ch,sizeof(ch),0);
				if(res < 0)
				{
					ERR_MSG("recv");
					return -1;
				}

				else if(res == 0)
				{
					printf("[%s : %d] newfd = %d 客户端下线__%d__\n",\
							inet_ntoa(saveCin[i-4].sin_addr),ntohs(saveCin[i-4].sin_port),i,__LINE__);

					close(i);

					FD_CLR(i,&readfds);

					int j = maxfd;

					for(;j>=0;j--)
					{
						if(FD_ISSET(j,&readfds))
						{
							break;
						}
					}
					maxfd = j;
					continue;

				}
				printf("[%s : %d] newfd = %d : %s__%d__\n", \
						inet_ntoa(saveCin[i-4].sin_addr), ntohs(saveCin[i-4].sin_port), i, ch, __LINE__);
				strcat(ch,"*_*");
				if(send(i,ch,sizeof(ch),0) < 0)
				{
					ERR_MSG("send");
					return -1;
				}
				printf("发送成功\n");
			}
		}
	}

	close(server_fd);

	return 0;
}

 poll客户端

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <poll.h>

#define ERR_MSG(msg) do{\
    fprintf(stderr, "line:%d ", __LINE__);\
    perror(msg);\
}while(0)

#define IP "192.168.0.153"   
#define PORT 7777

int main(int argc, const char *argv[])
{
    //创建
    int cfd = socket(AF_INET, SOCK_STREAM, 0); 
    if(cfd < 0)
    {   
        ERR_MSG("socket");
        return -1; 
    }   
    printf("cfd = %d\n", cfd);

    //允许端口快速重用
    int reuse = 1;
    if(setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {   
        ERR_MSG("setsockopt");
        return -1; 
    }   
    printf("允许端口快速重用成功\n");
    
    struct sockaddr_in sin;
    sin.sin_family      = AF_INET;     
    sin.sin_port        = htons(PORT) ;    
    sin.sin_addr.s_addr = inet_addr(IP);   


    //连接服务器
    if(connect(cfd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
    {   
        ERR_MSG("connect");
        return -1; 
    }   
    printf("connect success __%d__\n", __LINE__);

    //创建文件描述集合
    struct pollfd fds[2];

    fds[0].fd = 0;            
    fds[0].events = POLLIN;     

    fds[1].fd = cfd;        
    fds[1].events = POLLIN;    
    
    char buf[128] = ""; 
    ssize_t res = 0;
    int p_res = -1; 
    while(1)
    {   
        p_res = poll(fds, 2, -1);
        if(p_res < 0)
        {
            ERR_MSG("poll");
            return -1; 
        }
        else if(0 == p_res)
        {
            printf("time out.......\n");
            break;
        }
    
      
        if((fds[0].revents & POLLIN)!=0)  
        {
            bzero(buf, sizeof(buf));
            //发送 
            printf("触发键盘输入事件>>>");
            fgets(buf, sizeof(buf), stdin);
            buf[strlen(buf)-1] = 0;

            if(send(cfd, buf, sizeof(buf), 0) < 0)
            {
                ERR_MSG("send");
                return -1; 
            }
            printf("发送成功\n");
        }

        if(fds[1].revents & POLLIN)
        {
            //接收
            bzero(buf, sizeof(buf));
            res = recv(cfd, buf, sizeof(buf), 0); 
            if(res < 0)
            {
                ERR_MSG("recv");
                return -1; 
            }
            else if(0 == res)
            {
                printf("cfd=%d 服务器下线__%d__\n",  cfd, __LINE__);
                break;
            }
            printf("cfd=%d : %s __%d__\n",  cfd, buf, __LINE__);

        }

    }   


    close(cfd);

    return 0;
}

 select客户端

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>

#define IP "192.168.0.153"
#define PORT 7777
#define ERR_MSG(msg) do{\
	fprintf(stderr, "__%d__", __LINE__);\
	perror(msg);\
}while(0)
 
int main(int argc, const char *argv[])
{
	//创建流式套接字
	int sfd = socket(AF_INET,SOCK_STREAM, 0);
	if(sfd<0)
	{
		ERR_MSG("socket");
		return -1;
	}
	printf("socket success\n");
	//填充要来链接的服务器的窗口和ip
	
	struct sockaddr_in sin;
	sin.sin_family       =AF_INET;
	sin.sin_port         =htons(PORT);
	sin.sin_addr.s_addr  =inet_addr(IP);
	
	if(connect(sfd, (struct sockaddr*)&sin, sizeof(sin))<0)
	{
		ERR_MSG("connect");
		return -1;
	}
	printf("connect success\n");
 
	fd_set readfds, tempfds;
 
	FD_ZERO(&readfds);
	FD_ZERO(&tempfds);
 
	FD_SET(0, &readfds);
	FD_SET(sfd, &readfds);
 
	int maxfd = sfd;
	int st_res=0;
 
	
	char buf[128]="";
	ssize_t res;
	while(1)
	{
		tempfds = readfds;
		st_res = select(maxfd+1, &tempfds, NULL, NULL, NULL);
		if(st_res<0)
		{
			ERR_MSG("select");
			return -1;
		}
		else if(0==st_res)
	{
			printf("time out ..\n");
			break;
		}
		if(FD_ISSET(0, &tempfds))
		{
 
 
			bzero(buf, sizeof(buf));
			printf("请输入>>>>");
			fgets(buf, sizeof(buf), stdin);
			buf[strlen(buf)-1]=0;
			//发送
			if(send(sfd, buf, sizeof(buf), 0)<0)
			{
				ERR_MSG("send");
				return -1;
			}
			printf("send success\n");
		}
		//接收
		if(FD_ISSET(sfd, &tempfds))
		{
			bzero(buf, sizeof(buf));
 
			res=recv(sfd, buf, sizeof(buf), 0);
			if(res<0)
			{
				ERR_MSG("recv");
				return -1;
			}
			else if(0==res)
			{
				printf("服务器关闭\n");
				break;
			}
			printf(":%s\n", buf);
		}
	}
 
	close(sfd);
 
 
 
 
	
 
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值