epoll()实现的tcp回射服务器和客户端

代码是从别的地方抄来的,如有错漏请多多包涵

client.c 

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include <poll.h>
#include <sys/epoll.h>
#include "common.h"
//#include <netdb.h>
//#include <netinet/in.h>
//#include <sys/uio.h>
//#include <sys/wait.h>
//#include <sys/un.h>

void str_cli(FILE *fp, int sockfd)
{
    char sendline[MAXLINE], recvline[MAXLINE];
    int len;

    //从终端获取一行字符串,将其写入套接字
    //然后从套接字一行字符串,将其写入终端
    while (fgets_s(sendline, MAXLINE, fp) != NULL)
    {
        write_s(sockfd, sendline, strlen(sendline));
        len = read_s(sockfd, recvline, MAXLINE);
        if (len == 0)
            err_quit("str_cli: server terminated prematurely");
        recvline[len] = 0;
        fputs(recvline, stdout);
    }
}

int main(int argc, char **argv)
{
    int sockfd;
    struct sockaddr_in servaddr;
    if (argc != 2)
        err_quit("ustruct sockaddrge: client <IPAddress>");

    //创建用于TCP协议的套接字
    sockfd = socket_s(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(SERV_PORT);

    //将程序的参数1(argv[1])转换成套接字地址结构
    inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
    向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
    connect_s(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    str_cli(stdin, sockfd);
    return 0;
}

server.c

#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
#include <time.h>
#include <sys/wait.h>
#include <poll.h>
#include <sys/epoll.h>
#include "common.h"

int main(int argc, char **argv)
{
    int listenfd, connfd, sockfd, epfd;
    int i, maxi, nfds;
    ssize_t n;
    char buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in cliaddr;
    struct sockaddr_in servaddr;

    //声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
    struct epoll_event ev, events[256];

    //创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大
    epfd = epoll_create(256);

    //创建用于TCP协议的套接字
    listenfd = socket_s(AF_INET, SOCK_STREAM, 0);
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    //把socket和socket地址结构联系起来
    bind_s(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    //开始监听LISTENQ端口
    listen_s(listenfd, LISTENQ);

    //设置与要处理的事件相关的文件描述符和事件
    ev.data.fd = listenfd;
    ev.events = EPOLLIN | EPOLLET;

    //注册epoll事件
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
    maxi = 0;

    while (1)
    {
        //等待epoll事件的发生
        //返回需要处理的事件数目nfds,如返回0表示已超时。
        nfds = epoll_wait(epfd, events, 20, 500);

        //处理所发生的所有事件
        for (i = 0; i < nfds; ++i)
        {
            //如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接。
            if (events[i].data.fd == listenfd)
            {
                connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);
                printf("connection from %s, port %d.\n", inet_ntop(AF_INET, (void *)&cliaddr.sin_addr, buf, sizeof(buf)), ntohs(cliaddr.sin_port));

                //设置用于读操作的文件描述符和事件
                ev.data.fd = connfd;
                ev.events = EPOLLIN | EPOLLET;

                //注册事件
                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
            }

            //如果是已经连接的用户,并且收到数据,那么进行读入。
            else if (events[i].events & EPOLLIN)
            {
                sockfd = events[i].data.fd;
                if (sockfd < 0)
                    continue;
                n = read(sockfd, buf, MAXLINE);
                if (n < 0)
                {
                    // Connection Reset:你连接的那一端已经断开了,
                    //而你却还试着在对方已断开的socketfd上读写数据!
                    if (errno == ECONNRESET)
                    {
                        close_s(sockfd);
                        events[i].data.fd = -1;
                    }
                    else
                        err_quit("read error");
                }
                //如果读入的数据为空
                else if (n == 0)
                {
                    close_s(sockfd);
                    events[i].data.fd = -1;
                }
                else
                {
                    //设置用于写操作的文件描述符和事件
                    ev.data.fd = sockfd;
                    ev.events = EPOLLOUT | EPOLLET;
                    //注册事件
                    epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
                }
            }

            //如果有数据发送
            else if (events[i].events & EPOLLOUT)
            {
                sockfd = events[i].data.fd;
                write_s(sockfd, buf, n);

                //设置用于读操作的文件描述符和事件
                ev.data.fd = sockfd;
                ev.events = EPOLLIN | EPOLLET;

                //注册事件
                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
            }
        }
    }
    return 0;
}

common.c

#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <time.h>
#include <sys/wait.h>
#include "common.h"

sig_t signal_s(int __sig, sig_t __handler)
{
    sig_t ret = signal(__sig, __handler);
    if (ret == SIG_ERR)
        err_quit("signal error");

    return ret;
}

int select_s(int __nfds, fd_set *__restrict__ __readfds, fd_set *__restrict__ __writefds,
             fd_set *__restrict__ __exceptfds, struct timeval *__restrict__ __timeout)
{
    int ret = select(__nfds, __readfds, __writefds, __exceptfds, __timeout);
    if (ret < 0)
        err_quit("select error");
    return ret;
}

ssize_t read_s(int __fd, void *__buf, size_t __nbytes)
{
    int ret = read(__fd, __buf, __nbytes);
    if (ret < 0)
        err_quit("read error");

    return ret;
}

int shutdown_s(int __fd, int __how)
{
    int ret = shutdown(__fd, __how);
    if (ret < 0)
        err_quit("shutdown error");
    return ret;
}

int socket_s(int socket_family, int socket_type, int protocol)
{
    int sockfd = socket(socket_family, socket_type, protocol);
    if (sockfd < 0)
    {
        perror("create socket error");
        exit(EXIT_FAILURE);
    }
    return sockfd;
}

int bind_s(int __fd, const struct sockaddr *__addr, socklen_t __len)
{
    int ret = bind(__fd, __addr, __len);
    if (ret < 0)
    {
        perror("bind socket fail");
        exit(EXIT_FAILURE);
    }
    return ret;
}

int listen_s(int __fd, int __n)
{
    int ret = listen(__fd, __n);
    if (ret < 0)
    {
        perror("listen error");
        exit(EXIT_FAILURE);
    }
    return ret;
}

int connect_s(int __fd, const struct sockaddr *__addr, socklen_t __len)
{
    int ret = connect(__fd, __addr, __len);
    if (ret < 0)
    {
        perror("connect eror");
        exit(EXIT_FAILURE);
    }
    return ret;
}

ssize_t write_s(int __fd, const void *__buf, size_t __n)
{
    int ret = write(__fd, __buf, __n);
    if (ret < 0)
        err_quit("write error");

    return ret;
}



void err_quit(char *message)
{
    printf("%s\n", message);
    exit(EXIT_FAILURE);
}

in_addr_t inet_addr_s(const char *__cp)
{
    in_addr_t ret = inet_addr(__cp);
    if (ret < 0)
        perror("inet_addr error");
    return ret;
}

int fork_s(void)
{
    int ret;

    ret = fork();
    if (ret < 0)
        err_quit("fork error");

    return ret;
}

char *fgets_s(char *__restrict__ __s, int __n, FILE *__restrict__ __stream)
{
    char *rptr;
    if ((rptr = fgets(__s, __n, __stream)) == NULL && ferror(__stream))
        err_quit("fgets error");
    return rptr;
}

int close_s(int fd)
{
    int ret = close(fd);
    if (ret < 0)
        err_quit("close error");

    return ret;
}

static int read_cnt;
static int *read_ptr;
static int read_buf[MAXLINE];

/* 一直读,知道读取到了东西为止, 放在read_buf里面, 然后还获取了最后一个字节 */
static int my_read(int fd, char *ptr)
{
    if (read_cnt <= 0)
    {
    again:
        if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0)
        {
            if (errno == EINTR)
                goto again;
            return (-1);
        }
        else if (read_cnt = 0)
            return 0;
        read_ptr = read_buf;
    }

    read_cnt--;
    *ptr = *read_ptr++;
    return (-1);
}

ssize_t readline(int fd, void *vptr, size_t maxlen)
{
    ssize_t n, rc;
    char c, *ptr;

    ptr = vptr;

    for (n = 1; n < maxlen; n++)
    {
        if ((rc = my_read(fd, &c)) == 1)
        {
            *ptr++ = c;
            if (c == '\n')
                break;
        }
        else if (rc == 0)
        {
            *ptr = 0;
            return (n - 1);
        }
        else
            return (-1);
    }

    *ptr = 0;
    if (n < 0)
        err_quit("readline error");

    return n;
}

void fputs_s(const char *__restrict__ __s, FILE *__restrict__ __stream)
{
    if (fputs(__s, __stream) == EOF)
        err_quit("fputs erro");
}

common.h

#ifndef _COMMON_H_
#define _COMMON_H_

#define SERV_PORT 1043
#define MAXLINE 4096
#define LISTENQ 1024

#define min(a, b) ((a) < (b) ? (a) : (b))
#define max(a, b) ((a) < (b) ? (b) : (a))

int socket_s(int socket_family, int socket_type, int protocol);
int bind_s(int __fd, const struct sockaddr *__addr, socklen_t __len);
int listen_s(int __fd, int __n);
int connect_s(int __fd, const struct sockaddr *__addr, socklen_t __len);
in_addr_t inet_addr_s(const char *__cp);
int fork_s(void);
int close_s(int fd);
void err_quit(char *message);
ssize_t write_s(int __fd, const void *__buf, size_t __n);
char *fgets_s(char *__restrict__ __s, int __n, FILE *__restrict__ __stream);
ssize_t readline(int fd, void *vptr, size_t maxlen);
void fputs_s(const char *__restrict__ __s, FILE *__restrict__ __stream);
int select_s(int __nfds, fd_set *__restrict__ __readfds, fd_set *__restrict__ __writefds,
             fd_set *__restrict__ __exceptfds, struct timeval *__restrict__ __timeout);
ssize_t read_s(int __fd, void *__buf, size_t __nbytes);
int shutdown_s(int __fd, int __how);

#endif

运行:

root@orangepizero2:~/test# ./server.rap
connection from 0.0.0.0, port 0.
^C
root@orangepizero2:~/test#
 


root@orangepizero2:~/test# ./client.rap  192.168.3.95
ce shui hui she xin xi
ce shui hui she xin xi
 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值