服务器多并发代码(多线程与多进程)

1 /**********************hsj**************************/                                                                                                                          
    2 #include<stdio.h>
    3 #include<stdlib.h>
    4 #include<string.h>
    5 #include<unistd.h>
    6 #include<sys/types.h>
    7 #include<sys/socket.h>
    8 #include<arpa/inet.h>
    9 #include<pthread.h>
   10 #define IP "192.168.2.140"
   11 #define PORT 8000
   12 
✹ 13 int main(int argc, char* argv[]){
   14     int pid;    
   15     char buf[1024];
   16     int lfd = socket(AF_INET , SOCK_STREAM , 0);
   17     if(lfd < 0){
   18         perror("socket error");
   19         exit(1);
   20     }
   21     struct sockaddr_in seraddr, cliaddr;
   22     seraddr.sin_family = AF_INET;
   23     seraddr.sin_port = htons(PORT);
   24    // int dst;
   25    // inet_pton(AF_INET,IP,(void*)&dst);
   26    // seraddr.sin_addr.s_addr = dst;
   27     seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
   28     int optval = 1;
   29     setsockopt(lfd , SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
   30     int rr = bind(lfd , (struct sockaddr*)&seraddr, sizeof(seraddr));
   31     if(rr < 0){
   32         perror("bind error");
   33         exit(1);
   34     }
   35     listen(lfd , 64);
   36     socklen_t addrlen = sizeof(cliaddr);
   37     while(1){
   38         int cfd = accept(lfd, (struct sockaddr*)&cliaddr,&addrlen);
   39         char arr[64];
   40         inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, arr, 64); 
   41         printf("client is ok IP: %s, port: %d\n",arr,ntohs(cliaddr.sin_port));
   42         pid = fork();
   43         if(pid == 0){
   44             close(lfd);
   45             while(1){
   46                 rr = read(cfd, buf ,1024);
   47                 if(rr == 0){
   48                     printf("客户端断开连接\n");
   49                     close(cfd);
   50                     return 0;
   51                 }
   52                 else if(rr < 0){
   53                     perror("read error");
   54                     exit(1);
   55                 }
   56                 write(STDOUT_FILENO, buf, rr);
   57                 write(cfd, buf, rr);
   58             }
   59 
   60         }
   61         close(cfd);
   62         
   63     }
   64     return 0;
   65 }
   66 /***************************************************/

这是多进程的服务器代码.
解决IP地址变化的问题:
【之前IP地址写在代码里,IP动态变化,需要经常改代码】
将inetpton改为一个宏   

seraddr.sin_addr.s_addr = htonl(INADDR_ANY);//该宏为0.0.0.0(即是0)

让其取监听本地的IP地址,无论你的地址变成什么都没有问题

之前是宏定义IP,现在是直接给IP赋值,而inet_pton需要IP,htonl也可以得到网络字节序

解决nc只能连接一个客户端的问题(只有一个 accept):

设置一个属性:端口复用    setsockopt

获取属性getsockoppt

int setsockopt(int sockfd, socklen_t *)

sockfd:文件描述符

level:一个宏

允许地址复用:SO_REUSEADDR

允许端口复用:SO_REUSEPORT

optname:宏

optval:opt是选项,val是值,是一个数(存缓冲区)

0是不允许,1是允许

optlen:选项的长度(缓冲区的长度)

/**********************hsj**************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<error.h>
#define IP "192.168.2.140"
#define PORT 8000
void* client(void* arg)
{
    int rr;
    int cfd = *((int*)arg);
    char buf[1024];
 	while(1)
    {
        rr = read(cfd, buf, 1024);
        if(rr == 0)
        {
            printf("客户端断开连接\n");
            close(cfd);
            pthread_exit(NULL);
        }
        else if(rr < 0)
        {
            perror("read error");
            pthread_exit(NULL);
        }
        write(STDOUT_FILENO, buf, rr);
        write(cfd, buf, rr);
    }
}
int main(int argc, char* argv[]){
    pthread_t tid;
    int lfd = socket(AF_INET , SOCK_STREAM , 0);
    if(lfd < 0){
        perror("socket error");
        exit(1);
    }
    struct sockaddr_in seraddr, cliaddr;
    seraddr.sin_family = AF_INET;
    seraddr.sin_port = htons(PORT);
   // int dst;
   // inet_pton(AF_INET,IP,(void*)&dst);
   // seraddr.sin_addr.s_addr = dst;
    seraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    int optval = 1;
    setsockopt(lfd , SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    int rr = bind(lfd , (struct sockaddr*)&seraddr, sizeof(seraddr));
    if(rr < 0){
        perror("bind error");
        exit(1);
    }
    listen(lfd , 64);
    socklen_t addrlen = sizeof(cliaddr);
    while(1){
        int cfd = accept(lfd, (struct sockaddr*)&cliaddr,&addrlen);
        char arr[64];
        inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, arr, 64); 
        printf("client is ok IP: %s, port: %d\n",arr,ntohs(cliaddr.sin_port));
        int ret = pthread_create(&tid, NULL,client,(void*)&cfd);
        if(ret > 0){
            printf("pthread_create error:%s\n", strerror(ret));
            pthread_exit(NULL);
        }
    }
    return 0;
}
/***************************************************/

这是服务器多线程的代码

思考一个问题:

client读取标准输入,写到buf缓冲区中,再讲buf缓冲区中的东西写入到cfd文件描述符中(描述的是socket管道)。

然后阻塞,等待服务器端写入,再读取写到标准输出。可以看到,读取的是cfd,但是之前客户端却写入了cfd,若是服务器除了什么问题,那么有没有可能客户端是在自己读自己。(因为这是回发服务器,对其来说写和回是相同的)

这与之前的C—S间发送信息的接收端和发送端有关。首先,客户端在自己的read上阻塞等待输入,当我们输入数据时,客户端将输入的数据写在buf里,再将buf里的数据写在cfd套接字的发送端中,此时我们的服务器从cfd的发送端缓冲区读出数据,再把读出的数据打在标准输出中,再写入cfd套接字的接收端缓冲区,此时到了客户端读到了数据写在buf里,再从buf里打印数据形成回射。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值