Linux網絡編程echo簡單示例2--select實現

//select_echo_server.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdarg.h>

//max socket fd can process
#define MAX_FD        1024
//!server ip
#define SERVER_IP     "127.0.0.1"
//!server bind port default
#define SERVER_PORT   11111

//macros for simple log
#define log_msg(level,fmt,...)   do { fprintf(stderr,"[%s][%s %s - line:%d]"fmt"\n",level,__DATE__,__TIME__,__LINE__,##__VA_ARGS__);}while (0);

#define debug(fmt,...)            log_msg("DEBUG",fmt,##__VA_ARGS__)
#define info(fmt,...)           log_msg("INFO ",fmt,##__VA_ARGS__)
#define warn(fmt,...)           log_msg("WARN ",fmt,##__VA_ARGS__)
#define error(fmt,...)          log_msg("ERROR",fmt,##__VA_ARGS__)

//create an socket and liten at the specified port
int create_and_listen(const char *szIP,uint16_t nPort)
{
    //socket
    int server_fd = socket(AF_INET,SOCK_STREAM,0);
    if (server_fd < 0)
    {
        error("socket failed,errno=%d",errno);
        return -1;
    }

    //addr structure
    struct sockaddr_in sa;
    memset(&sa,0,sizeof(sa));
    sa.sin_addr.s_addr=inet_addr(szIP);
    sa.sin_port       =htons(nPort);
    sa.sin_family     =AF_INET;

    //rause the addr
    int rause = 1;
    int optlen= 4;
    if (setsockopt(server_fd,SOL_SOCKET,SO_REUSEADDR,(const char *)&rause,optlen) == -1)
    {
        error("setsockopt failed,errno=%d",errno);
        close(server_fd);
        return -1;
    }

    //bind
    if (bind(server_fd,(struct sockaddr *)&sa,sizeof(sa)) == -1)
    {
        error("bind failed,errno=%d",errno);
        close(server_fd);
        return -1;
    }

    //listen
    if (listen(server_fd,15) == -1)
    {
        error("listen failed,errno=%d",errno);
        close(server_fd);
        return -1;
    }

    info("create_and_listen end ,server_fd=%d",server_fd);

    return server_fd;
}

//handle client request
int doClient(int client_fd)
{
#if 1
    int result = 0;
    struct sockaddr_in client_sa;
    memset(&client_sa,0,sizeof(client_sa));
    socklen_t socklen = 0;
    //getpeername
    if (getpeername(client_fd,(struct sockaddr *)&client_sa,&socklen) == -1)
    {
        error("getpeername failed,client_fd=%d,errno=%d",client_fd,errno);
        return -1;
    }
    char buf[1024]={0};
    int read_size=0;
    int send_size=0;
    read_size=recv(client_fd,buf,sizeof(buf)-1,0);
    if (read_size < 0)
    {
        info("read failed,client_fd",client_fd);
    }
    else if (read_size==0)
    {
        info("read EOF,client_fd",client_fd);
    }
    else
    {
        send_size=send(client_fd,buf,read_size,0);
        if (send_size==read_size)
        {
            info("recv and echo msg success,msg=%s",buf);
            result = 1;
        }
        else
        {
            error("send failed,read_size=%d,send_size=%d,msg=%s",read_size,send_size,buf);
        }
    }
    return result==1?0:-1;
#endif
}

int main(int argc,char *argv[])
{
    const char *szIP=SERVER_IP;
      uint16_t nPort=SERVER_PORT;
    int server_fd = create_and_listen(szIP,nPort);
    if (server_fd < 0)
    {
        exit(0);
    }

    //fd set
    int fdset[MAX_FD] = {0};
    fd_set rdset;
    fd_set wrset;
    int max_fd = 0;
    memset(fdset,0xff,sizeof(fdset));
    while (1)
    {
        int fdset_c=0;
        FD_ZERO(&rdset);
        FD_SET(server_fd,&rdset);
        max_fd = server_fd;
        for (int i=0;i<MAX_FD;++i)
        {
            if (fdset[i]!=-1)
            {
                fdset_c++;
                if (i>max_fd)
                {
                    max_fd=i;
                }
                FD_SET(i,&rdset);
            }
        }
        debug("fdset_c=%d,max_fd=%d",fdset_c,max_fd);
        struct timeval tv;
        tv.tv_sec=1;
        tv.tv_usec=0;
        int select_return = select(max_fd+1,&rdset,NULL,NULL,&tv);
        if (select_return == -1)
        {
            error("select failed,errno=%d",errno);
            break;
        }
        else if(select_return <= 0)
        {
            info("[main] do loop report,server listen ip=%s,port=%d",szIP,nPort);
        }
        else
        {
            if (FD_ISSET(server_fd,&rdset))
            {
                struct sockaddr_in client_sa;
                socklen_t socklen = 0;
                memset(&client_sa,0,sizeof(client_sa));
                //accept
                int client_fd=accept(server_fd,(struct sockaddr *)&client_sa,&socklen);
                if (client_fd < 0)
                {
                    error("accept failed,errno=%d",errno);
                    break;
                }
                else if (client_fd >= MAX_FD)
                {
                    warn("client_fd >= MAX_FD,client_fd=%d,max_fd=%d",client_fd,MAX_FD);
                    close(client_fd);
                    //continue;
                }
                else
                {
                    info("accept from %s:%d",inet_ntoa(client_sa.sin_addr),ntohs(client_sa.sin_port));
                    fdset[client_fd]=0;
                }
            }
            for (int i=0;i<MAX_FD;++i)
            {
                if (fdset[i]!=-1 && FD_ISSET(i,&rdset))
                {
                    if (doClient(i) < 0)
                    {
                        close(i);
                        fdset[i]=-1;
                    }
                }
            }
        }
    }

    info("[main] end");
    //close
    close(server_fd);
    return 0;
}


//echo_client.c
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define log_msg(level,fmt,...)   do { fprintf(stderr,"[%s][%s %s - line:%d]"fmt"\n",level,__DATE__,__TIME__,__LINE__,##__VA_ARGS__);}while (0);

#define debug(fmt,...)			log_msg("DEBUG",fmt,##__VA_ARGS__)
#define info(fmt,...)           log_msg("INFO ",fmt,##__VA_ARGS__)
#define warn(fmt,...)           log_msg("WARN ",fmt,##__VA_ARGS__)
#define error(fmt,...)          log_msg("ERROR",fmt,##__VA_ARGS__)

#define checkif(cond,fmt,...)   do\
								{\
								if(!(cond))\
									{\
									error(fmt,##__VA_ARGS__);\
									exit(0);\
									}\
								} while(0);

//default server bind address info
#define SERVER_IP      "127.0.0.1"
#define SERVER_PORT    11111 

int main()
{
	//socket
	int client_fd = socket(AF_INET,SOCK_STREAM,0);
	checkif(client_fd>0,"socket failed , error=%d",errno);
	info("socket success, socket=%d",client_fd);
	struct sockaddr_in sa;
	memset(&sa,0,sizeof(sa));
	sa.sin_family        = AF_INET;
	sa.sin_port          = htons(SERVER_PORT);
	sa.sin_addr.s_addr   = inet_addr(SERVER_IP);

	//bind
	if (connect(client_fd,(struct sockaddr *)&sa,sizeof(struct sockaddr_in)) != 0)
	{
		error("connect failed ,socket=%d, error=%d",client_fd,errno);
		exit(0);
	}

	info("connect to server success, socket=%d,server_ip=%s,server_port=%d",client_fd,SERVER_IP,SERVER_PORT);

	while(1)
	{
		char szMsg[128] = {0};
		printf("please input an string : \n");
		if (NULL == gets(szMsg))
		{
			break;
		}
		ssize_t send_size = send(client_fd,szMsg,strlen(szMsg),0);
		if (send_size > 0)
		{
			info("send msg to server,msg=%s ,size=%d",szMsg,send_size);
		}
		else
		{
			warn("send msg to server failed ,size=%d ,errno=%d",send_size,errno);
			break;
		}
		//recv
		char szBuf[128] = {0};
		ssize_t recv_size = recv(client_fd,szBuf,sizeof(szBuf)-1,0);
		if (recv_size > 0)
		{
			info("recv msg from server success ,msg=%s,recv_size=%d",szBuf,recv_size);
		}
		else
		{
			warn("recv msg from server failed,recv_size=%d ,errno=%d",recv_size,errno);
			break;
		}
	}

	//close
	info("client end");
	//close server
	close(client_fd);
	return 0;
}


發佈了22 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章