高并发服务器-多线程

为了流量券,冲

B站就业班视频

28_哔哩哔哩_bilibili

比较起来,还是多进程的服务器更好,用线程函数写的代码,有如下俩问题:

1.客户端刚关闭的时候,服务器压根不知道,要关了再连接的时候,服务器才反应过来。

我自己分析原因:对应 线程执行函数,读取服务器数据 n=read() 当n <=0 时,因为函数一直在这里阻塞,所以收不到n=0的信号(我的见解不知道对不对)

2.主线程应该关闭accept函数产生的文件描述符newfd,现在找不到写主线程代码的地方 - -

3.线程与线程之间,两种文件描述符(监听,处理信息)都是共享的,如果想让它们实现不同享,需要先构建一个结构体Allinfo,把客户端地址sockadd_in,文件描述符,线程号包起来,再利用数组的元素内存地址不同,把这个大结构体Allinfo的指针传到线程回调函数里 当参数 ,太麻烦了,后面没听讲

//多线程 的 高并发服务器。注意添加pthread.h头文件
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include<netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <pthread.h>

//先声明线程回调函数calbak
void * calbak (void *arg){
    int *fd2 =(int *) arg;
    //这个函数里面应该无法打印客户端地址了(ip和端口)因为这个局部变量不认识dst 
    //printf("child process,IP:%s,PORT: %d\n", inet_ntop(AF_INET, &dst.sin_addr.s_addr,addstring,sizeof(addstring)),ntohs(dst.sin_port));
    //其次,把客户端发送过来的数据读出来
    int i =0;
    int n =0;
    char buf[1024];
    while (1){
        memset(buf,0x00,sizeof(buf));
     	n = read (*fd2,buf,sizeof(buf));
       	if (n<=0){
             printf("有一个客户端已关闭,或者读到的字符为0/n");
	     break; 
        }
        for (i=0;i<n;i++){
            buf[i] =toupper(buf[i]);
        }
    	//把数据传回客户端,变成大写了已经
        write (*fd2, buf, n);
   }
//关闭通信描述符,其实通信描述符是newfd,作为参数传进来了,现在转化为*fd2整数。
close(*fd2);
pthread_exit(NULL);
}

int main() {
    int sfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sfd <0){
        printf("socket fun error/n");
        return -1;
    }
    //定义客户端地址serad
    struct sockaddr_in serad;
    //外部客户可以连接本机任意IP地址。端口设置为8888
    bzero(&serad, sizeof(serad));
    serad.sin_family =AF_INET;
    serad.sin_port =htons(8888);
    serad.sin_addr.s_addr = htonl (INADDR_ANY);

    int ret = bind(sfd, (struct sockaddr *)&serad, sizeof(serad));
    if (ret<0) {
        printf("bind error/n");
        return -1;
    }
    //将socket从主动变为被动(服务器必备),这样可以监听来自客户的请求
    listen( sfd,128);   
    
    // int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
    //addr是传出参数,保留客户的地址,所以这是客户地址

    //定义客户端地址dst,dst的端口也是8888
    struct sockaddr_in dst;
    pthread_t thnum;
    int newfd;	
    while (1) {
        bzero(&dst, sizeof(dst));
        dst.sin_family =AF_INET;
        dst.sin_port =htons(8888);
        socklen_t dstleng = sizeof(dst);
	//接收一个客户端的连接请求,得到信息传递描述符newfd
	//并把这个newfd作为参数,传进子线程的执行函数(回调函数)中 
	newfd = accept (sfd, (struct sockaddr* )&dst, &dstleng);
        if (newfd <0) {
	    printf("服务端,accept error、\n");
            return -1;
        }
	//打印客户端地址和端口,	
        char addstring[128];
        memset(addstring, 0x00,128);
        printf("服务器端,还没有创建新线程,客户端地址是:\n");
        printf("IP:%s,PORT: %d\n", inet_ntop(AF_INET, &dst.sin_addr.s_addr,addstring,sizeof(addstring)),ntohs(dst.sin_port));
	//创建新的线程,让主线程负责监听,子线程负责收发信息
	int ret2 = pthread_create(&thnum,NULL,calbak,&newfd);	
	if( ret2!= 0) {
	    printf("创建新线程失败\n");
	    return -1;
	}
	//设置线程分离属性,让子线程结束的时候自己回收资源,避免成为僵尸线程
	pthread_detach(thnum);
    }
    //关闭监听描述符
    close(sfd);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值