您的位置:首页 > 理论基础 > 计算机网络

基于TCP协议用多线程实现并发服务器,实现思路、算法和demo

2017-07-18 20:46 561 查看
基本的思路:用主线程负责client的连接, 然后当有客户端来连接的时候,创建子进程。在子进程里面实现数据的接收。


1.myhead.h

先把一些要用的API的头文件都写进来。

[cpp] view
plain copy

#ifndef _MYHEAD_H_  

#define _MYHEAD_H_  

  

#include <stdio.h>  

#include <sys/types.h>  

#include <sys/socket.h>  

#include <netinet/in.h>  

#include <string.h>  

#include <unistd.h>  

#include <sys/wait.h>  

#include <pthread.h>  

  

#define MYPORT 6667         //1024以下的是保留的端口号,用大于1024的;  

//#define MYADDR "192.168.1.102"         //把这行注释掉,可以在调用客户端程序时,输入服务器运行的IP来连接服务器 ./client 192.168.1.233  

  

#endif  

2.server.c

[cpp] view
plain copy

#include "myhead.h"  

  

void *read_msg(void *argc);  

  

int main()  

{  

    int ret = 0;  

    int socketfd = 0;                               //局部变量保存在栈空间,而栈空间是脏的==》里面还是保存的是上一次这个区域里面保存的值;  

    int clientfd = 0;  

      

    pid_t pid = 0;  

    pthread_t th = 0;  

      

      

    struct sockaddr_in sock_server = {0};           //变量类型保存在netinet/in.h里面的;  

    struct sockaddr_in sock_client = {0};           //保存连接的客户端那边的信息;  

      

    socklen_t len = sizeof(struct sockaddr);  

      

    //第一步:创建套接字;  

    socketfd = socket(AF_INET,SOCK_STREAM,0);  

    if(socketfd == -1)      //入口检查  

    {  

        perror("socket");    //打印错误信息  

        return -1;  

    }  

    printf("socket success...\n");                  //确保前面的代码是运行正确的;  

      

    //第二步:给套接字绑定必要的信息;  

    sock_server.sin_family = AF_INET;               //给服务程序绑定地址族;  

    sock_server.sin_port = htons(MYPORT);           //给服务器程序设定个端口号;  

//  sock_server.sin_addr.s_addr = inet_addr(MYADDR);//给服务程序绑定IP地址;  

    sock_server.sin_addr.s_addr = htonl(INADDR_ANY);//绑定任意ip地址;这样就能够实现像之前说的./client 192.168.1.233这样使用  

      

    ret = bind(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));  

    if(ret == -1)  

    {  

        perror("bind");  

        return -1;  

    }  

    printf("bind success..\n");  

      

    //第三步:listen监听!  

    ret = listen(socketfd,10);  

    if(ret == -1)  

    {  

        perror("listen");  

        return -1;  

    }  

    printf("listen success...\n");  

      

//这里的第四步accept放到下面的while(1)里面,有许多client要连接到服务器中来      

//  clientfd = accept(socketfd,(struct sockaddr *)&sock_client,&len);  

//  if(clientfd == -1)  

//  {  

//      perror("accept");  

//      return -1;  

//  }  

//  printf("accept success...clinet fd = %d\n",clientfd);  

      

    while(1)  

    {  

        clientfd = accept(socketfd,(struct sockaddr *)&sock_client,&len);  

        if(clientfd == -1)  

        {  

            perror("accept");  

            return -1;  

        }  

        printf("accept success... clientfd = %d\n",clientfd);   //客户端连接进来,  

        ret = pthread_create(&th,NULL,read_msg,&clientfd);      //执行read_msg这个函数。传递clientfd,要知道从哪一个客户端来读取数据;  

        if(ret != 0)  

        {  

            perror("pthread_create");  

            return -1;  

        }  

    }  

    close(socketfd);  

      

    return 0;  

}  

  

void *read_msg(void *argc)  

{  

    //argc首先是void类型的指针,经过(int *)argc强制转化为int *的指针,接下来要从argc所指向的地址里面取值;  

    //===>*((int *)argc);===>经过以上的操作就将pthread_create()里面传递的参数,赋值给fd;  

      

    int fd = *((int *)argc);  

    printf("fd = %d\n",fd);     //验证fd是否等于main函数里面的cleintfd;    4  

      

    char recvbuff[20] = {0};   //用来保存接收的信息  

    int recvcnt = 0;              //用来存recv函数的返回值  

      

    while(1)  

    {  

        bzero(recvbuff,sizeof(recvbuff));     //先清空recvbuff里面的内容。  

        recvcnt = read(fd,recvbuff,sizeof(recvbuff));    //从recvbuff中读取,sizeof(recvbuff)大小的内容到为文件描述符fd的文件中  

        if(recvcnt == -1)  

        {  

            perror("recv");  

            return NULL;  

        }  

        else if(recvcnt == 0)             

        {  

            printf("The Client is closed!\n");  

            break;  

        }  

        else  

        {  

            printf("Recv from Client %d bytes,data:%s\n",recvcnt,recvbuff);  //打印接收到的信息  

        }  

        if(strcmp(recvbuff,"end") == 0)  

        {  

            break;  

        }  

    }  

    close(fd);  

      

    return NULL;  

}  

3.client.c

[cpp] view
plain copy

#include "myhead.h"  

  

//int main()  

int main(int argc,char **argv)  

{  

    //参数入口检查;  

    if(argc != 2)              //usage: ./client 192.168.1.233  

    {  

        perror("argc");  

        return -1;  

    }  

    int socketfd = 0;  

    int ret = 0;  

      

    struct sockaddr_in sock_server = {0};  

      

    socketfd = socket(AF_INET,SOCK_STREAM,0);        //第一步还是创建套接字  

    if(-1 == socketfd)  

    {  

        perror("socket");  

        return -1;  

    }  

    printf("socket success...\n");  

      

    //用sock_server提醒你们这边连接的是服务器端的IP地址和端口号;  

    sock_server.sin_family = AF_INET;  

    sock_server.sin_port = htons(MYPORT);  

//  sock_server.sin_addr.s_addr = inet_addr(MYADDR);  

    sock_server.sin_addr.s_addr = inet_addr(argv[1]);  

      

    ret = connect(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));        //连接服务器  

    if(ret == -1)  

    {  

        perror("connect");  

        return -1;  

    }  

      

    char sendbuff[20] = {0};  

    int sendcnt = 0;  

      

    while(1)  

    {  

        //第一步:提示客户输入要发送的数据;  

        printf("Please input a string:\n");  

        scanf("%s",sendbuff);  

          

        //第二步:调用send向套接字发送数据;  

//      sendcnt = send(socketfd,sendbuff,strlen(sendbuff),0);  

        sendcnt = write(socketfd,sendbuff,strlen(sendbuff));  

        if(sendcnt == -1)  

        {  

            perror("send");  

            return -1;  

        }  

        else  

        {  

            printf("Send to Server %d bytes,data:%s\n",sendcnt,sendbuff);  

        }  

        //第三步:判断发送的数据是否是end,如果是,就结束;  

        if(strcmp(sendbuff,"end") == 0)  

        {  

            close(socketfd);  

            break;  

        }  

    }  

          

    return 0;  

}  

分别编译服务器和客户端程序: 
gcc server.c -o server 
gcc client.c -o client 
然后,先运行服务器./server,再运行客户端./client,客户端发消息给服务器,服务器回复,实现基本的一收一发的功能。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: