简单的客户端与服务端实现

一、客户端

/*
 * @Author: D-lyw 
 * @Date: 2018-10-26 14:06:32 
 * @Last Modified by: D-lyw
 * @Last Modified time: 2018-11-16 12:34:08
 * @name tcp_client.c
 * @descripe    实现最基本的创建套接字, 填充客户端信息,connet连接服务端, 可连续向服务端发送消息
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
extern int errno;

#define SERVERPORT 1001

int main(int argc, char const *argv[])
{
    // 定义变量存储本地套接字描述符
    int clifd;
    // 服务端ip地址
    const char serverIp[] = "10.243.0.160";
    // 定义套接字结构存储套接字的ip,port等信息
    struct sockaddr_in cliaddr_in;
    // 定义发送,接收缓冲区大小
    char sendBuf[1024], recvBuf[1024];
    // 创建套接字
    if((clifd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
        fprintf(stderr, "创建套接字失败,%s\n", strerror(errno));
        exit(errno);
    }
    // 填充服务器端结构体信息
    cliaddr_in.sin_family = AF_INET;
    cliaddr_in.sin_addr.s_addr = inet_addr(serverIp);
    cliaddr_in.sin_port = htons(SERVERPORT);
    // 请求连接服务器进程
    if(connect(clifd, (struct sockaddr *)&cliaddr_in, sizeof(struct sockaddr)) == -1){
        fprintf(stderr,"请求连接服务器失败, %s\n", strerror(errno));
        exit(errno);
    }
    strcpy(sendBuf, "hi,hi, severs!\n");
    // 发送打招呼消息
    if(send(clifd, sendBuf, 1024, 0) == -1){
        fprintf(stderr, "send message error:(, %s\n", strerror(errno));
        exit(errno);
    }
    //接收服务器传回的数据
    recv(clifd, recvBuf, 1024, 0);
    printf("get message from server :  %s\n", recvBuf);
    while(1){
        fgets(sendBuf, 1024, stdin);
        printf("sendBuf is %s\n", sendBuf);
        if(send(clifd, sendBuf, 1024, 0) == -1){
            fprintf(stderr, "send message error:(, %s\n", strerror(errno));
        }

        recv(clifd, recvBuf, 1024, 0);
        printf("get message from server :  %s\n", recvBuf);
    }
    close(clifd);
    return 0;
}

二、服务端

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

#define MAXLINE 50
#define OPEN_MAX 100
#define LISTENQ 20
#define SERV_PORT 5000
#define INFTIM 1000

void setnonblocking(int sock)
{
    int opts;
    opts = fcntl(sock, F_GETFL);
    if (opts < 0) {
        perror("fcntl(sock,GETFL)");
        exit(1);
    }
    opts = opts | O_NONBLOCK;
    if (fcntl(sock, F_SETFL, opts) < 0) {
        perror("fcntl(sock,SETFL,opts)");
        exit(1);
    }
}

int main(int argc, char *argv[])
{
    int i, maxi, connfd, sockfd, nfds, portnumber = 1001;
    ssize_t n;
    char line[MAXLINE];
    socklen_t clilen;

    // 声明epoll_event结构体的变量,ev用于注册事件,数组用于回传要处理的事件
    struct epoll_event ev, events[20];
    // 生成用于处理accept的epoll专用的文件描述符
    int epfd = epoll_create(256);
    struct sockaddr_in clientaddr;
    struct sockaddr_in serveraddr;
    int listenfd = socket(AF_INET, SOCK_STREAM, 0);
    // 把socket设置为非阻塞方式
    setnonblocking(listenfd);
    // 设置与要处理的事件相关的文件描述符
    ev.data.fd = listenfd;
    // 设置要处理的事件类型
    ev.events = EPOLLIN | EPOLLET;
    // 注册epoll事件
    epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev);
    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    char *local_addr = "10.243.0.160";
    inet_aton(local_addr, &(serveraddr.sin_addr));
    serveraddr.sin_port = htons(portnumber);
    bind(listenfd, (sockaddr *)&serveraddr, sizeof(serveraddr));
    listen(listenfd, LISTENQ);
    maxi = 0;
    cout << "start working" << endl;
    for (;;) {
        // 等待epoll事件的发生,如果没有事件发生,epoll_wait函数会一直阻塞
		// epoll_wait函数的作用就是把需要监控的fd直接交给内核,让内核来判断哪个fd有数据到来,
        nfds = epoll_wait(epfd, events, 20, 500);
        // 处理所发生的所有事件
        for (i = 0; i < nfds; ++i) {
            if (events[i].data.fd == listenfd) { // 如果新监测到一个SOCKET用户连接到了绑定的SOCKET端口,建立新的连接
                connfd = accept(listenfd, (sockaddr *)&clientaddr, &clilen);
                if (connfd < 0) {
                    perror("connfd<0");
                    exit(1);
                }
                setnonblocking(connfd);
                char *str = inet_ntoa(clientaddr.sin_addr);
                cout << "accapt a connection from " << str << endl;
                cout << "create a connfd : " << connfd << endl;
                // 设置用于读操作的文件描述符
                ev.data.fd = connfd;
                // 设置用于注测的读操作事件
                ev.events = EPOLLIN | EPOLLET;
                // 注册ev
                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev);
            } else if (events[i].events & EPOLLIN) { // 如果是已经连接的用户,并且收到数据,那么进行读入
                if ((sockfd = events[i].data.fd) < 0) {
                    continue;
                }
				
				cout << "EPOLLIN Event fd = " << events[i].data.fd << endl;
				
				n = read(sockfd, line, MAXLINE);
                if (n < 0) {
                    if (errno == ECONNRESET) {
                        close(sockfd);
                        events[i].data.fd = -1;
                    } else {
                        std::cout << "readline error" << std::endl;
                    }
                } else if (n == 0) {
                    close(sockfd);
                    events[i].data.fd = -1;
                } else {   // 正常接收数据
					cout << "get datd size n = " << n << endl;
					line[n] = '/0';
					cout << "read " << line << endl;
					// 设置用于写操作的文件描述符
					ev.data.fd = sockfd;
					// 设置用于注测的写操作事件
					ev.events = EPOLLOUT | EPOLLET;
					// 修改sockfd上要处理的事件为EPOLLOUT
					epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
				}
            } else if (events[i].events & EPOLLOUT) { // 如果有数据发送
                cout << "EPOLLOUT Event fd = " << sockfd << endl;
                sockfd = events[i].data.fd;
                char str[MAXLINE] = "hi hi I am server!!!";
                strcpy(line, str);
                write(sockfd, line, MAXLINE);
                // 设置用于读操作的文件描述符
                ev.data.fd = sockfd;
                // 设置用于注测的读操作事件
                ev.events = EPOLLIN | EPOLLET;
                // 修改sockfd上要处理的事件为EPOLIN
                epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev);
            } else if (events[i].events & EPOLLERR) {
				// 传输出错
			}
        }
    }
	
    return 0;
}

你可能感兴趣的:(网络编程,网络)