网络编程——TCP并发服务器(线程实现)

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define PORT 10086        //定义端口号为多少

void *dosth(void *arg);      //线程调用函数

int main(void)
{
      

    //先创建socket连接,规定好设备与设备之间的通讯协议为 IPV4  TCP 协议             
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    if(sockfd<0){
        perror("socket error");
        exit(-1);
    }

    //更改sockfd的属性,允许地址重复:防止报“地址重复”错误
    int on = 1;
    setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));

    //绑定:设置好本地的通讯协议是什么,端口号和IP地址分别为多少
    struct sockaddr_in myself;
    myself.sin_family = AF_INET;          //设置本地通讯协议为 IPV4  TCP 协议      
    myself.sin_port = htons(PORT);      /*设置本地端口号,注意:由于PORT在本地为小端序,而网络传输需要用大端序来传输,所以这里需要用htons()函数来将PORT转换为大端序*/   

    myself.sin_addr.s_addr = htonl(INADDR_ANY);        //设置本地的IP地址

    if(bind(sockfd,(struct sockaddr *)&myself,sizeof(myself))){        //绑定本地属性,使用bind()函数,来让上面设置好的本地属性生效
        perror("bind error");
        exit(-1);
    }    

    //监听:将主动连接变成被动连接,即:设置为只能等待被其他设备连接,而不能主动的去连接其他设备,这就是服务器端。
    if(listen(sockfd,30)){        // 30表示最大只允许连接30个设备
        perror("listen error");
        exit(-1);
    }

    //客户端的IP地址与PORT信息,用client变量来存储
    struct sockaddr_in client;
    int len = sizeof(client);
    int fd;
    int m=20;
    pthread_t thread;
    while(1){
        //等待客户连接
        fd = accept(sockfd,(struct sockaddr *)&client,&len);          /*当客户端与该服务端连接好后,将客户端的IP地址与PORT信息传给client变量来存储(由&client我们可以看得出来,该函数会使用解引用*,来改变main中client变量的值)。注意:每次连接成功都会产生一个新的文件描述符fd*/
        if(fd<0){
            if(!(m--)){                 //m = 20,即:某个客户被允许连接失败次数为20次,如果20次还没有连接成功,则打印"accept error"
                    perror("accept error");
            }
        }else{
            m=20;
            
            /*开线程:注意:thread是一个变量,而不是一个线程的名字。每次成功开一个线程后,都会产生一个新的thread值,(由&thread我们可以看得出来,该函数会使用解引用*,来改变main中thread变量的值),所以,每当客户连接成功后,thread变量的值就会变化,而不同的thread值对应不同的线程。所以,每次有客户连接成功后,就会开辟不同的线程,而不是共用一个线程*/
            if(pthread_create(&thread,NULL,dosth,&fd)){               /*注意:每次开辟一个线程后,都会开辟一个独立的栈来执行dosth()函数。所以,不同的线程,它们的dosth()函数是各自在各自的栈中执行,互不干扰。由于函数是在栈中运行的,所以栈的大小决定了线程可以开多少*/
                perror("pthread_create error");
            }
            

            //将线程设置为分离属性,当线程结束后,会自动自己释放资源空间
            pthread_detach(thread);      


       }
   }
   
   return 0;
}

//线程函数

void *dosth(void *arg)
{
    int fd = *(int *)arg;

    char buf[20];
    char buff[10]="牛逼";
    //接受数据,转发数据
    int ret;
    while(1){
        bzero(buf,sizeof(buf));
        ret = recv(fd,buf,sizeof(buf),0);        //接收客户发来的信息,将信息赋值给buf数组
        if(ret<=0){
            close(fd);
            pthread_exit(NULL);
        }else{
            printf("%s\n",buf);                //打印buf数组中的信息
            send(fd,buff,strlen(buff),0);
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值