socket C/S多线程编程

移植部分list.h

#ifndef _LIST_H
#define _LIST_H
#include <stddef.h>
//通过结构体成员指针获取结构体指针位置
#define container_of(ptr, type, member) (                  \
    {                                                      \
        const typeof(((type *)0)->member) *__mptr = (ptr); \
        (type *)((char *)__mptr - offsetof(type, member)); \
    })

//链表结构体
struct list_head
{
    struct list_head *next, *prev;
};

//链表初始化
static inline void INIT_LIST_HEAD(struct list_head *list)
{
    list->next = list;
    list->prev = list;
}

#ifndef CONFIG_DEBUG_LIST
static inline void __list_add(struct list_head *new,
                              struct list_head *prev,
                              struct list_head *next)
{
    next->prev = new;
    new->next = next;
    new->prev = prev;
    prev->next = new;
}
#else
extern void __list_add(struct list_head *new,
                       struct list_head *prev,
                       struct list_head *next);
#endif

//添加至链表首部
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

//添加到链表尾部
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}

//判断链表是否为空
/**
 * list_empty - tests whether a list is empty
 * @head: the list to test.
 */
/* if empty return 1,else 0 */
static inline int list_empty(const struct list_head *head)
{
    return head->next == head;
}

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
    next->prev = prev;
    prev->next = next;
}

//删除操作
static inline void list_del(struct list_head *entry)
{
    __list_del(entry->prev, entry->next);
    entry->next = NULL;
    entry->prev = NULL;
}

//获取链表的数据指针
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

//遍历链表
#define list_for_each(pos, head) \
    for (pos = (head)->next; pos != (head); pos = pos->next)

//遍历过程中如果对链表有删除操作需要使用这个接口
#define list_for_each_safe(pos, n, head)                   \
    for (pos = (head)->next, n = pos->next; pos != (head); \
         pos = n, n = pos->next)

//遍历链表元素
#define list_for_each_entry(pos, head, member)                 \
    for (pos = list_entry((head)->next, typeof(*pos), member); \
         &pos->member != (head);                               \
         pos = list_entry(pos->member.next, typeof(*pos), member))

#define list_for_each_entry_safe(pos, n, head, member)          \
    for (pos = list_entry((head)->next, typeof(*pos), member),  \
        n = list_entry(pos->member.next, typeof(*pos), member); \
         &pos->member != (head);                                \
         pos = n, n = list_entry(n->member.next, typeof(*n), member))

//取第一个元素
#define list_first_entry(ptr, type, member) \
    list_entry((ptr)->next, type, member)

//自定义消息结构体
struct msg
{
    int msgid;
    char msginfo[50];
    struct list_head list;
};

#endif

server.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/shm.h>
#include <pthread.h>
#include "list.h"

#define MYPORT 8887
#define QUEUE 20
#define BUFFER_SIZE 1024
int server_sockfd;
struct list_head c_list;
struct n_session
{
    struct sockaddr_in client_addr;
    socklen_t length;
    int cli_fd;
    pthread_t recv_tid;
    pthread_t send_tid;
    char name[20];
    struct list_head list;
    int idx;
};

void action(int sig)
{
    printf("ctrl+c close fd sig is %d\n", sig);
    close(server_sockfd);
    exit(0);
}

void *new_session_recv(void *arg)
{
    struct n_session *new_cli = arg;
    struct n_session *pos;
    char rbuffer[BUFFER_SIZE];
    while (1)
    {
        memset(rbuffer, 0, sizeof(rbuffer));
        int len = recv(new_cli->cli_fd, rbuffer, sizeof(rbuffer), 0);
        if (len < 0)
        {
            printf("server recv err %d, client :%s\n", len, new_cli->name);
            break;
        }
        else if (len == 0)
        {
            printf("client[%s] is shutdown\n", new_cli->name);
            break;
        }
        printf("recv from [%s] len is %d,message :%s\n", new_cli->name, len, rbuffer);
        if (strcmp(rbuffer, "exit\n") == 0)
            break;
    }
    close(new_cli->cli_fd);
    list_del(&new_cli->list);
    free(new_cli);
    return NULL;
}

void *new_session_send(void *arg)
{
    struct n_session *new_cli = arg;
    struct n_session *pos;
    char tbuff[BUFFER_SIZE];
    memset(tbuff, 0, sizeof(tbuff));
    while (1)
    {
        list_for_each_entry(pos, &c_list, list)
        {
            printf("start send to all client\n");
            send(pos->cli_fd, tbuff, strlen(tbuff), 0);
        }
        sleep(2);
    }
    close(new_cli->cli_fd);
    list_del(&new_cli->list);
    free(new_cli);
    return NULL;
}

int main()
{
    int ret;
    ///定义sockfd
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    ///定义sockaddr_in
    struct sockaddr_in server_sockaddr;
    server_sockaddr.sin_family = AF_INET;
    server_sockaddr.sin_port = htons(MYPORT);
    server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    signal(SIGINT, action);
    signal(SIGTERM, action);
    INIT_LIST_HEAD(&c_list);
    ///bind,成功返回0,出错返回-1
    if (bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr)) == -1)
    {
        perror("bind");
        exit(1);
    }

    ///listen,成功返回0,出错返回-1
    if (listen(server_sockfd, QUEUE) == -1)
    {
        perror("listen");
        exit(1);
    }
    int idx = 0;
    while (1)
    {
        struct n_session *new_cli = malloc(sizeof(struct n_session));
        memset(new_cli, 0, sizeof(struct n_session));
        new_cli->length = sizeof(new_cli->client_addr);
        new_cli->cli_fd = accept(server_sockfd, (struct sockaddr *)&new_cli->client_addr, &new_cli->length);
        if (new_cli->cli_fd < 0)
        {
            perror("accept");
            break;
        }
        typeof(int *) hell;
        sprintf(new_cli->name, "cli(%d)", ntohs(new_cli->client_addr.sin_port));
        new_cli->idx = idx;
        printf("a new client has connectted [%d],name is %s\n", idx, new_cli->name);
        list_add_tail(&new_cli->list, &c_list);
        ret = pthread_create(&new_cli->recv_tid, NULL, new_session_recv, new_cli);
        if (ret < 0)
        {
            printf("pthread_create err\n");
            break;
        }
        pthread_detach(new_cli->recv_tid);
        ret = pthread_create(&new_cli->recv_tid, NULL, new_session_send, new_cli);
        if (ret < 0)
        {
            printf("pthread_create err\n");
            break;
        }
        pthread_detach(new_cli->send_tid);
        idx++;
    }
    close(server_sockfd);
    return 0;
}

client.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <pthread.h>
#include <signal.h>

#define MYPORT 8887
#define BUFFER_SIZE 1024

int sock_cli;

void *session_recv(void *arg)
{
    char rbuffer[BUFFER_SIZE];
    while (1)
    {
        memset(rbuffer, 0, sizeof(rbuffer));
        int len = recv(sock_cli, rbuffer, sizeof(rbuffer), 0);
        if (len < 0)
        {
            printf("client recv err %d\n", len);
            break;
        }
        else if (len == 0)
        {
            printf("server is shutdown\n");
            break;
        }
        printf("recv from server len is %d,message :%s\n", len, rbuffer);
        if (strcmp(rbuffer, "exit\n") == 0)
            break;
    }
    close(sock_cli);
    return NULL;
}

void *session_send(void *arg)
{
    int ret;
    char tbuffer[BUFFER_SIZE];
    while (fgets(tbuffer, sizeof(tbuffer), stdin) != NULL)
    {
        ret = send(sock_cli, tbuffer, strlen(tbuffer), 0); ///发送
        if (ret < 0)
        {
            perror("send");
            break;
        }
        if (strcmp(tbuffer, "exit\n") == 0)
            break;
    }
    close(sock_cli);
    return NULL;
}

void action(int sig)
{
    printf("ctrl+c close fd sig is %d\n", sig);
    close(sock_cli);
    exit(0);
}

int main()
{
    int ret = 0;
    ///定义sockfd
    sock_cli = socket(AF_INET, SOCK_STREAM, 0);
    signal(SIGTERM, action);
    signal(SIGINT, action);
    ///定义sockaddr_in
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(MYPORT);                 ///服务器端口
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ///服务器ip

    ///连接服务器,成功返回0,错误返回-1
    if (connect(sock_cli, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
    {
        perror("connect");
        exit(1);
    }
    printf("connect server ok\n");
    pthread_t recv_tid, send_tid;
    ret = pthread_create(&recv_tid, NULL, session_recv, NULL);
    if (ret < 0)
    {
        printf("pthread_create err\n");
    }
    pthread_detach(recv_tid);
    ret = pthread_create(&send_tid, NULL, session_send, NULL);
    if (ret < 0)
    {
        printf("pthread_create err\n");
    }
    pthread_detach(send_tid);
    while (1)
        ;
    close(sock_cli);
    return 0;
}

简单Makefile

CC = gcc
CFLAG := -lpthread
INC := I./

all : server client pthread

server:
	$(CC)  -o server server.c $(CFLAG)
client:
	$(CC)  -o client client.c $(CFLAG)
pthread:
	$(CC)  -o pthread pthread.c $(CFLAG)
clean:
	rm -rf server client pthread 
	killall -15 server
	killall -15 client

多客户端和服务器之间的交互

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值