梁越

网络编程学习笔记9-第一个netcat的实现(thread-per-connection)

0 人看过

实现简单的netcat,每次读开一个线程,视频p20

本笔记参考的视频链接:https://www.bilibili.com/video/BV1Ht411p7wx?p=20
库链接:https://github.com/chenshuo/muduo
参考链接:https://blog.csdn.net/MonroeD/article/details/71252365

下面的程序是一个简单的netcat的实现

这里是thread-per-connection的实现,针对连接数目不多的情况,每次读开一个线程,负责从stdin写到socket

在服务端和客户端进行编译,我这里是

g++ netcat_thread.cc -o netcat_thread -lpthread

你自己改成对应的名字,而且-lpthread是必须的,因为程序使用了pthread库

编译完成就可以运行了

服务端:

./netcat_thread -l 12345

客户端:

./netcat_thread 192.168.200.134 12345
#include <stdio.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include <sys/socket.h>  
#include <netinet/in.h> 
#include <unistd.h>
#include <arpa/inet.h>
#include <error.h>
#include <strings.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <linux/tcp.h>
#include <signal.h>
#include <arpa/inet.h>
#define MAX 8192
#define SIZE 10

void* readsock(void *arg)
{
        int *sock = (int *)arg;
        char buf[MAX];
        int nr;
        while ( (nr = recv(*sock, buf, sizeof(buf), 0)) > 0)
        {
                int nw = write(STDOUT_FILENO, buf, nr);
                if (nr < nw)
                {
                        break;
                }
        }
        printf("connection closed by peer.\n");
        exit(0); //should somehow nofity main thread
}

void readstdin(int sockfd)
{
        char buf[MAX];
        int nr;
        while ( (nr = read(STDIN_FILENO, buf, sizeof(buf))) > 0)
        {
                int nw = send(sockfd, buf, nr, 0);
                if (nw < nr)
                {
                        break;
                }
        }
}

void run(int sockfd)
{
        //read from sock to stdout
        pthread_t pid;
        pthread_create(&pid, NULL, readsock, (void*)&sockfd);

        //read from stdin to sockfd
        readstdin(sockfd);

        //close, fixme
        close(sockfd);
        pthread_join(pid,NULL);
}

int main(int argc, char **argv)
{
        //sigpipe
        signal(SIGPIPE, SIG_IGN);
        if (argc < 3)
        {
                printf("Usage:\n  %s hostname port\n  %s -l port\n", argv[0], argv[0]);
                return 0;
        }

        int port = atoi(argv[2]);

        if (strcmp(argv[1], "-l") == 0)
        {
                struct sockaddr_in address;
                bzero(&address, sizeof(address));
                address.sin_family = AF_INET;
                address.sin_addr.s_addr = INADDR_ANY;
                address.sin_port = htons(port);

                int listenfd = socket(AF_INET, SOCK_STREAM, 0);
                assert(listenfd >= 0);

                //address reuse and no nagle
                int reuse = 1;
                setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
                setsockopt(listenfd,  IPPROTO_TCP, TCP_NODELAY, &reuse, sizeof(reuse));

                int ret = bind(listenfd, (struct sockaddr*)&address, sizeof(address));
                assert(ret >= 0);

                ret = listen(listenfd,5);
                assert(ret >= 0);
                //printf("Listening...\n"); 
                struct sockaddr_in client;
                int len = sizeof(client);
                int sockfd = accept(listenfd, (struct sockaddr *)(&client), (socklen_t*)&len);
                assert(sockfd > 0);

                run(sockfd);
        }
        else
        {
            int sockfd;
            struct sockaddr_in ser;
            bzero(&ser,sizeof(ser));
            sockfd = socket(AF_INET,SOCK_STREAM,0);

            ser.sin_family = AF_INET;
            ser.sin_addr.s_addr = inet_addr(argv[1]);
            if(argv[2])
            {
                 ser.sin_port = htons(port);   
            }
            ser.sin_port = htons(12345);
            connect(sockfd, (struct sockaddr*)&ser, sizeof(ser));

            run(sockfd);
        }

        return 0;
}

最近真的很忙,忙到没空学习了,等过了这一两周一定会赶上进度