移植部分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