【自留】C创建一个socket服务端

【自留】C创建一个socket服务端

猿掌柜
2023-09-18 / 1 评论 / 9 阅读 / 正在检测是否收录...

用C创建一个服务端
ARM版Linux 测试通过
接收、发送(建议不要这么使用)均使用了线程
里面是自用的函数,包括不用的
**线程thread_send如果用了while 会让CPU彪到100%,建议不要这么使用~~~
创建线程的时候建议不要创建此线程**
client_socket 为外部线程引用
引用tcp_server.h(代码如下)

#ifndef _TCP_SERVER_H_
#define _TCP_SERVER_H_

int client_socket;
int flag;

#endif

client_socket是我外面使用的

文件名tcp_server.c

#include "tcp_server.h"
#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 <ctype.h>
#include <pthread.h>
#include<errno.h>
int client_socket;
int flag;


#define MAXCONN 2
#define ERRORCODE -1
#define BUFFSIZE 1024
int count_connect = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

struct pthread_socket
{
    int socket_d;
    pthread_t thrd;
};

static void *thread_send(void *arg)
{
    //char buf[BUFFSIZE];
    int sd = *(int *) arg;
    client_socket=sd;
    //memset(buf, 0, sizeof(buf));
    //strcpy(buf, "hello,welcome to you! \n");
    char buferr[] = { 0xa5,0x5a,0x01,0x01,0xb5,0x5b };
    if (send(sd, buferr, strlen(buferr), 0) == -1)
    {
        printf("send error:%s \n", strerror(errno));
        return NULL;
    }
    while (1)
    {
        memset(buferr, 0, sizeof(buferr));
        read(STDIN_FILENO, buferr, sizeof(buferr));
        if (send(sd, buferr, strlen(buferr), 0) == -1)
        {
            printf("send error:%s \n", strerror(errno));
            break;
        }
    }
    return NULL;
}
///receive data
static void* thread_recv(void *arg)
{
    char buf[BUFFSIZE];
    struct pthread_socket *pt = (struct pthread_socket *) arg;
    int sd = pt->socket_d;
    pthread_t thrd = pt->thrd;
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        int rv = recv(sd, buf, sizeof(buf), 0); //是阻塞的
        if (rv < 0)
        {
            flag=0;
            printf("recv error:%s \n", strerror(errno));
            break;
        }
        if (rv == 0) // 这种情况说明client已经关闭socket连接
        {
            flag=0;
            break;
        }
        if(buf[0]==8){
            flag=1;
        }
        else if(buf[0]==7){
            flag=0;
        }
        //printf("recv length :%d \n", rv);
        //printf("receive :%d\n", buf[0]); //输出接受到内容
    }
        
    pthread_cancel(thrd);
    pthread_mutex_lock(&mutex);
    count_connect--;
    pthread_mutex_unlock(&mutex);
    close(sd);
    return NULL;
}
static int create_listen(int port)
{
 
    int listen_st;
    struct sockaddr_in sockaddr; //定义IP地址结构
    int on = 1;
    listen_st = socket(AF_INET, SOCK_STREAM, 0); //初始化socket
    if (listen_st == -1)
    {
        printf("socket create error:%s \n", strerror(errno));
        return ERRORCODE;
    }
    if (setsockopt(listen_st, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) //设置ip地址可重用
    {
        printf("setsockopt error:%s \n", strerror(errno));
        return ERRORCODE;
    }
    sockaddr.sin_port = htons(port); //指定一个端口号并将hosts字节型传化成Inet型字节型(大端或或者小端问题)
    sockaddr.sin_family = AF_INET;    //设置结构类型为TCP/IP
    sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);    //服务端是等待别人来连,不需要找谁的ip
    //这里写一个长量INADDR_ANY表示server上所有ip,这个一个server可能有多个ip地址,因为可能有多块网卡
    if (bind(listen_st, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) == -1)
    {
        printf("bind error:%s \n", strerror(errno));
        return ERRORCODE;
    }

    if (listen(listen_st, 5) == -1) //     服务端开始监听
    {
        printf("listen error:%s \n", strerror(errno));
        return ERRORCODE;
    }
    return listen_st;
}
 
int accept_socket(int listen_st)
{
    int accept_st;
    struct sockaddr_in accept_sockaddr; //定义accept IP地址结构
    socklen_t addrlen = sizeof(accept_sockaddr);
    memset(&accept_sockaddr, 0, addrlen);
    accept_st = accept(listen_st, (struct sockaddr*) &accept_sockaddr,&addrlen);
    //accept 会阻塞直到客户端连接连过来 服务端这个socket只负责listen 是不是有客服端连接过来了
    //是通过accept返回socket通信的
    if (accept_st == -1)
    {
        printf("accept error:%s \n", strerror(errno));
        return ERRORCODE;
    }
       //printf("accpet ip:%s \n", inet_ntoa(accept_sockaddr.sin_addr));
    return accept_st;
}

void run_server(int port)
{
        int listen_st = create_listen(port);    //创建监听socket
        pthread_t send_thrd, recv_thrd;
        struct pthread_socket ps;
        int accept_st;
        if (listen_st == -1)
        {
            //return ERRORCODE;
        }
        printf("server start \n");
        while (1)
        {
            accept_st = accept_socket(listen_st); //获取连接的的socket
            if (accept_st == -1)
            {
                    //return ERRORCODE;
            }
            if (count_connect >= MAXCONN)
            {
                    printf("connect have already be full! \n");
                    close(accept_st);
                    continue;
            }
            pthread_mutex_lock(&mutex);
            count_connect++;
            pthread_mutex_unlock(&mutex);
            //if (pthread_create(&send_thrd, NULL, thread_send, &accept_st) != 0) //创建发送信息线程,不建议这么使用,会把CPU拉满
            //{
                //    printf("create thread error:%s \n", strerror(errno));
                //    break;
 
            //}
            client_socket=accept_st;
            //pthread_detach(send_thrd);        //设置线程可分离性,这样的话主线程就不用join
            ps.socket_d = accept_st;
            ps.thrd = send_thrd;
            if (pthread_create(&recv_thrd, NULL, thread_recv, &ps) != 0)//创建接收信息线程
            {
                    printf("create thread error:%s \n", strerror(errno));
                    break;
            }
            pthread_detach(recv_thrd); //设置线程为可分离,这样的话,就不用pthread_join
        }
    close(accept_st);
    close(listen_st);
    //return 0;
}
1

评论 (1)

取消
  1. 头像
    路过
    Windows 10 · Google Chrome

    学习了

    回复
  2. 头像
    猿长老 作者
    Windows 10 · QQ Browser

    生活,不会因你抱怨而改变;人生,不会因你惆怅而变化。你怨或不怨,生活一样;你愁或不愁,人生不变。抱怨多了,愁的是自己,惆怅多了,苦的还是自己。

    回复