Level6day4作业

1. 阅读以下程序,完成下面的a-c题:

listenfd = socket(…);
bind(listenfd,…);
listen(listenfd,…);

for ( ; ; ) {
connfd = accept(listenfd, …);
if (( pid = fork( )) == 0) {
recv(connfd,…);
send(connfd,…);
}
else
close(connfd);
}
根据上面的程序,对以下说法判断对错
a. 这是一个并发服务器( 对 )
b. 在任何时候,该服务器只能处理一个客户端的请求( 错 )
c. 随着服务器端接受越来越多的请求,connfd的值变得越来越大( 错 值不变 )

linux@ubuntu:~/projects/Level6day4_server_process/bin/x64/Debug$ ./Level6day4_server_process.out 
fd_client is :4
Clinet(192.168.0.158:43822) is connected!
handler thread: newfd =4
message is:hELLo wOLd!!!

message is:hELLo wOLd!!!

fd_client is :4
Clinet(192.168.0.158:43824) is connected!
handler thread: newfd =4
message is:hELLo wOLd!!!

message is:hELLo wOLd!!!

message is:hELLo wOLd!!!

message is:hELLo wOLd!!!

message is:hELLo wOLd!!!

fd_client is :4
Clinet(192.168.0.158:43826) is connected!
handler thread: newfd =4
message is:hELLo wOLd...

message is:hELLo wOLd!!!

可以看到 'fd_client is :4 ' ,fd_client的值一直保持不变。

2.请用多线程编写TCP服务器和客户端通信的代码,功能:一个服务器能处理多个客户端的请求:

(作业要求:做作业的时候不要再翻看视频上的教程,对函数理解不明白的全部通过man手册去查看,
自己思考框架,使用makefile编译,然后将测试的记录和结果添加到readme.txt文件中提交上来,代码实现完成测试通过后
再提交作业,网络部分学习不写代码不测试看不出问题的,良好的习惯帮助你们快速成长。)

server_pthread.cpp

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

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.0.158"

void* func_recall(void* arg);
char botton[64];

int main()
{
    int fd = -1;
    int result = 0,i=0;
    struct sockaddr_in mysockaddr;
    struct sockaddr_in clientscokaddr;
    socklen_t clientaddrlen;
    
    static pthread_t nptd;

    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    /*优化4: 允许绑定地址快速重用 */
    int b_reuse = 1;
    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &b_reuse, sizeof(int));

    /*2. 绑定 */
    /*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT);//网络字节序的端口号
#if 1    
    //mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
    mysockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
#else
    result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr);
    if (result != 1) {
        perror("inet_pton");
        return -1;
    }
#endif
    /*2.2 绑定 */
    result = bind(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
    if (result != 0) {
        perror("bind");
        return -1;
    }

    /*3. 调用listen()把主动套接字变成被动套接字 */
    result = listen(fd, 5);
    if (result != 0) {
        perror("listen");
        return -1;
    }

    /*4. 阻塞等待客户端连接请求 */

    /*优化2:通过程序获取刚建立连接的socket的客户端的IP地址和端口号*/
    int fd_client;
    while (1) {       
        bzero((void*)&clientscokaddr, sizeof(clientscokaddr));
        fd_client = accept(fd, (struct sockaddr*)&clientscokaddr, &clientaddrlen);
        if (-1 == result) {
            perror("accpet");
            return 0;
        }
        char ipv4_addr[16];
        if (!inet_ntop(AF_INET, (void*)&clientscokaddr.sin_addr, ipv4_addr, clientaddrlen)) {
            perror("inet_ntop");
            return -1;
        }

        printf("Clinet(%s:%d) is connected!\n", ipv4_addr, ntohs(clientscokaddr.sin_port));

        result = pthread_create(&nptd, 0, func_recall, (void*)&fd_client);
        if (result != 0) {
            perror("pthread_create");
            return -1;
        }
        i++;
    }

    close(fd);
    close(fd_client);
    return 0;
}

void* func_recall(void* arg) {
    int result = 0;
    int newfd = *(int*)arg;

    printf("handler thread: newfd =%d\n", newfd);
    //..和newfd进行数据读写
    char buf[BUFSIZ];
    

    while (1) {
        bzero(buf, BUFSIZ);

        do {
            result = read(newfd, buf, BUFSIZ - 1);
        } while (result < 0 && EINTR == errno);
        
        if (result < 0) {
            perror("read");
            break;
        }

        if (!result)
            break;

        printf("message is:%s\n", buf);
    }
    close(newfd);
    return 0;
}

--------------------------------------------分割线---------------------------------------------------------

client_pthread.cpp

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

#define SERV_PORT 5050
#define SERV_IP_ADDR "192.168.0.158"

int main()
{
    int fd = -1;
    int result = 0;
    struct sockaddr_in mysockaddr;
    char MESSAGE[] = "hELLo wOLd!!!\n";
    /* 1. 创建socket fd */
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }
    /*2.连接服务器 */

	/*2.1 填充struct sockaddr_in结构体变量 */
    bzero((void*)&mysockaddr, sizeof(mysockaddr));
    mysockaddr.sin_family = AF_INET;
    mysockaddr.sin_port = htons(SERV_PORT); //网络字节序的端口号
#if 0    
    mysockaddr.sin_addr.s_addr = inet_addr(SERV_IP_ADDR);
#else
    result = inet_pton(AF_INET, SERV_IP_ADDR, (void*)&mysockaddr.sin_addr);
    if (result != 1) {
        perror("inet_pton");
        return -1;
    }
#endif
    /*2.2  connect 链接服务端*/
    result = connect(fd, (struct sockaddr*)&mysockaddr, sizeof(mysockaddr));
    if (result != 0) {
        perror("connect");
        return -1;
    }
    printf("Client staring...OK!\n");

    /*3. 读写数据 */
    while (1) {
        do {
            result = write(fd, (void*)MESSAGE, sizeof(MESSAGE));
        } while (result < 0 && EINTR == errno);   //判断是否阻塞了     
        sleep(10);
    }

    close(fd);
    return 0;
}

Makefile for server

gcc -o server *.cpp -lpthread -Wall

Makefile for client

gcc -o client *.cpp  -Wall

测试结果展示