【ARM&Linux】并发服务器设计

《网络服务器的并发控制Demo,使用TCP》


1、源代码

/****************************************************************************************
* 文件名: service.c
* 创建者: 
* 时 间: 
* 联 系: 
* 简 介: TCP编程模型代码示例,并发服务器控制,函数API参考文档《Unix环境高级编程》
*****************************************************************************************/

/***********************************************************
函数学习及模型:
    1、创建套接字:int socket(int domain, int type, int protocol);
        参数一:指明域,例如AF_INET,表示ipv4域
        参数二:指明类型,如SOCK_STREAM表示tcp
        参数三:参数一和二都指明了,本参数填0
        返回值:成功0,失败-1

    2、绑定:int bind(int socket, const struct sockaddr *address,socklen_t address_len);
        参数一:指明的套接字
        参数二:指明服务端地址
        参数三:地址长度
        返回值:成功0,失败-1

    3、等待连接,是阻塞操作:int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
        参数一:指明套接字
        参数二:用于连接成功后,存储客户端地址的信息的结构
        参数三:客户端地址长度
        返回值:成功0, 失败-1
    4、收发数据:
        ssize_t send(int socket, const void *buffer, size_t length, int flags);
        ssize_t recv(int socket, void *buffer, size_t length, int flags);
        参数:flag一般填0

    5、关闭连接:int close(int fildes);


网络字节序一般以大端的形式,所以主机的字节序就需要相应的转换:

 host to net long

    uint32_t htonl(uint32_t hostlong);  //本地字节序转换为网络字节序
    uint16_t htons(uint16_t hostshort);

    uint32_t ntohl(uint32_t netlong);   //网络字节序转换为本地字节序
    uint16_t ntohs(uint16_t netshort);


IP地址字符面值与整数的相互转换:

    char *inet_ntoa(struct in_addr in);     // n to a 整型数据转换成字符串
    in_addr_t inet_addr(const char *cp);    // 字符串面值的ip地址转换为in_addr_t,并且已经转换成了网络字节序


函数:void bzero(void *s, size_t n);
功能:The  bzero()  function sets the first n bytes of the area starting at s to zero (bytes containing '\0').

************************************************************/


#include "mytype.h"

int main()
{
    int res;    //存储返回值
    char buf[64];
    pid_t pid;
    USE_TCP_SERVICE mysvc;
    mysvc.addr_length = sizeof(struct sockaddr_in);

    // 1、创建套接字
    if((mysvc.fd=socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        DEBUG_ERROR("service creat socket failed .\n");
        exit(EXIT_FAILURE);
    }

    // 2、绑定
    bzero(&mysvc.server_addr, mysvc.addr_length);   //清零
    mysvc.server_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //允许任何ip地址连入
    mysvc.server_addr.sin_port = htons(12306);      //端口号
    mysvc.server_addr.sin_family = AF_INET;         //指明ipv4域
    bind(mysvc.fd, (struct sockaddr_in *)&mysvc.server_addr, mysvc.addr_length);


    // 3、监听
    listen(mysvc.fd, 10);       //最多允许10个接入

    while(1)
    {
        mysvc.newfd = -1;       //重设
        // 3、等待连接
        mysvc.newfd = accept(mysvc.fd, (struct sockaddr_in *)&mysvc.client_addr, &mysvc.addr_length);

        // 4、连接成功后,创建新进程处理数据
        if(mysvc.newfd > 0)
        {
            DEBUG_INFO("[%s] to connected. \n", inet_ntoa(mysvc.client_addr.sin_addr));
            pid = fork();
            if(pid == 0)    //子进程
            {
                recv(mysvc.newfd, buf, strlen(buf), 0);
                DEBUG_INFO("receive data from [%s] : %s \n",inet_ntoa(mysvc.client_addr.sin_addr), buf);
                if( res = close(mysvc.newfd) == 0)
                {
                    DEBUG_INFO("[%s] to disconnected. \n");
                }else{
                    DEBUG_ERROR("[%s] close socket err. ErrCode: %d \n", inet_ntoa(mysvc.client_addr.sin_addr), res);
                }

                close(mysvc.newfd);
                close(mysvc.fd);
                exit(EXIT_SUCCESS);
            }
            close(mysvc.newfd);
        }
    } // end of while

    close(mysvc.fd);

    return 0;
}






/****************************************************************************************
* 文件名: client.c
* 创建者: 
* 时 间: 
* 联 系: 
* 简 介: tcp编程模型客户端,函数API参考文档《Unix环境高级编程》
*****************************************************************************************/
/***********************************************************
流程:
    1、创建套接字
    2、连接套接字
    3、发数据
    4、关闭套接字
************************************************************/


#include "mytype.h"

int main()
{
    char buf[64];
    USE_TCP_CLIENT mycli;
    mycli.addr_length = sizeof(struct sockaddr_in);

    // 1、创建套接字
    if((mycli.fd=socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        DEBUG_ERROR("client creat socket failed. \n");
        exit(EXIT_FAILURE);
    }

    // 2、连接套接字
    {
        bzero(&mycli.server_addr, mycli.addr_length);       //清零
        mycli.server_addr.sin_addr.s_addr = inet_addr("192.168.0.252"); //服务器ip地址
        mycli.server_addr.sin_port = htons(12306);                  //端口
        mycli.server_addr.sin_family = AF_INET;                     //ipv4域
    }
    if( connect(mycli.fd, (struct sockaddr_in *)&mycli.server_addr, mycli.addr_length) !=0 )
    {
        DEBUG_ERROR("connect failed , please again. \n");
        exit(EXIT_FAILURE);
    }

    // 3、发数据
    DEBUG_PRINTF("Please input : ");
    fgets(buf, sizeof(buf), stdin);
    send(mycli.fd, buf, strlen(buf), 0);

    // 4、关闭套接字
    close(mycli.fd);

    return 0;
}
/****************************************************************************************
* 文件名: mytype.h
* 创建者: Kun
* 联 系: [email protected]
* 简 介: linux常用类型定义
* 最后修改时间: 2018/2/15 17:57
*****************************************************************************************/

#ifndef _MYTYPE_H_
#define _MYTYPE_H_

//--------------------------< 预添加头文件包含 >----------------------//

#define USE_TIME 0
#define USE_SIGNAL 0
#define USE_SHARE_MEMORY 0
#define USE_SEMAPHORE_NAME 0
#define USE_SEMAPHORE_UNNAMED 0
#define USE_MSG_QUEUE 0
#define USE_FILE_CTL 0
#define USE_THREAD 0
#define USE_SOCKET 1
//-------------------------------< end ----------------------------//


//---------------------------< includes >---------------------------//
// c标准库头文件
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

// 信号使用相关头文件
#if USE_SIGNAL
#include <sys/signal.h>
#endif // USE_SIGNAL

// 有名信号量操作相关头文件
#if USE_SEMAPHORE
#include <sys/sem.h>
#include <sys/ipc.h>
#endif // USE_SEMAPHORE

// 无名信号量操作相关头文件
#if USE_SEMAPHORE_UNNAMED
    #include <semaphore.h>
#endif // USE_SEMAPHORE_UNNAMED

// 共享内存操作相关头文件
#if USE_SHARE_MEMORY
#include <sys/shm.h>
#endif // USE_SHARE_MEMORY

// 消息队列相关头文件
#if USE_MSG_QUEUE
    #if !USE_SEMAPHORE
        #include <sys/ipc.h>
    #endif
#include <sys/msg.h>
#endif // USE_MSG_QUEUE

// 系统调用式文件编程头文件
#include <fcntl.h>

// 该文件所定义的接口通常都是大量针对系统调用的封装,
// 如 fork、pipe 以及各种 I/O 原语(read、write、close 等等)。
#include <unistd.h>

// linux系统中类型定义相关头文件
#include <sys/types.h>

// 文件状态,是unix/linux系统定义文件状态所在的伪标准头文件。
#if USE_FILE_CTL
#include <sys/stat.h>
#endif // USE_FILE_CTL

// 时间编程相关头文件
#if USE_TIME
#include <sys/time.h>
#endif // USE_TIME


// 线程相关头文件
#if USE_THREAD
    #include <pthread.h>
#endif // USE_THREAD

// 网络编程相关头文件
#if USE_SOCKET
    #include <sys/socket.h>
    #include <arpa/inet.h>
    #include <netinet/in.h>
#endif // USE_SEMAPHORE_NAME
//-------------------------< includes end >-------------------------//


// bool类型定义
#ifndef bool
typedef unsigned int bool;
#endif
enum
{
    true = 1,
    false = !true
};

// 常用无符号数据类型定义
typedef unsigned int uint;
typedef unsigned char uchar;
typedef unsigned short ushort;

//----------------------< 调试信息输入相关宏定义 >----------------------//
#define DEBUG_INFO(...) printf("Info: "); printf(__VA_ARGS__)
#define DEBUG_ERROR(...) printf("Error: "); printf(__VA_ARGS__)
#define DEBUG_WARNING(...) printf("Warning: "); printf(__VA_ARGS__)
#define DEBUG_PRINTF(...) printf(__VA_ARGS__)
//------------------------------------------------------------------//

// 有名信号量使用封装结构
#if USE_SEMAPHORE
typedef struct sem_use SEM_USE;
struct sem_use
{
    int semid;
    key_t key;
    struct sembuf sops;
};
#endif // USE_SEMAPHORE

// 共享内存使用封装结构
#if USE_SHARE_MEMORY
typedef struct shmem_use SHMEM_USE;
struct shmem_use
{
    int shmid;
    key_t key;
};

#define BUF_SIZE 1024*1 //共享内存大小
typedef struct shmem_area SHMEM_AREA;
struct shmem_area
{
    bool isnull;
    char data[BUF_SIZE];
};

#endif // USE_SHARE_MEMORY

// 消息队列使用封装结构
#if USE_MSG_QUEUE
typedef struct msg_queue_use MSG_QUEUE_USE;
struct msg_queue_use{
    key_t key;
    int msgid;
};
#endif // USE_MSG_QUEUE

#if USE_SOCKET
//tcp客户端使用封装结构
typedef struct use_tcp_client{
    int fd;
    struct sockaddr_in server_addr;
    socklen_t addr_length;
}USE_TCP_CLIENT;
//tcp服务端使用结构封装
typedef struct use_tcp_service{
    int fd;
    int newfd;
    struct sockaddr_in server_addr;
    struct sockaddr_in client_addr;
    socklen_t addr_length;
}USE_TCP_SERVICE;

#endif // USE_SOCKET


#endif // _TYPE_H_




2、结果

  • Makefile
    引用块内容
  • 运行结果
    这里写图片描述

end..

猜你喜欢

转载自blog.csdn.net/qq153471503/article/details/79329893