主要功能:利用C/S模式,可以多台客服机于主机通信。
头文件:
#ifndef __head_h__
#define __head_h__
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <malloc.h>
/* 服务器要监听的本地端口 */
#define MYPORT 4000
/* 能够同时接受多少没有 accept 的连接 */
#define BACKLOG 10
// pthread_mutex_t work_mutex; /* protects both work_area and time_to_exit */
#define MAXDATASIZE 1024
extern char work_area[MAXDATASIZE];
typedef struct lk lk;
typedef struct ser_list ser_list;
struct lk{
struct lk *next;
};
struct ser_list {
lk *next;
int new_fd;
pthread_t pthread;
void *p_result;
int used_flag;
};
typedef struct list_header {
lk *next;
int len;
}list_header;
extern list_header freeheader;
extern list_header usedheader;
extern void InitFreeList(list_header *header);
extern void InitUsedList(list_header *used_header);
extern ser_list* FindBlock(list_header *free_header,list_header *used_header);
extern void Reclaim(list_header* free_header,list_header* used_header,ser_list* p);
#endif
LIST.C
#include "head.h"
char work_area[MAXDATASIZE];
list_header freeheader;
list_header usedheader;
void InitHeader(list_header *header)
{
header->len = 0;
header->next = NULL;
}
void InsertList(list_header *header)
{
int i;
i=0;
lk *p;
p = (lk *)malloc(sizeof(ser_list));
p->next = header->next;
header->next = p;
header->len++;
((ser_list*)p)->used_flag = 0;
}
void InitFreeList(list_header *free_header)
{
int i=0;
list_header *p;
lk *p_h;
InitHeader(free_header);
while(i++<BACKLOG) {
InsertList(free_header);
}
}
/*删除头节点后面一节点*/
ser_list * DeleteList(list_header *header)
{
ser_list *p;
p=(ser_list *)header->next;
if(p == NULL) return p;
header->next = ((ser_list *)(header->next))->next;
header->len--;
return p;
}
/*将节点A 插入末尾*/
void AddList(list_header *header,lk *p)
{
p->next = header->next;
header->next = p;
header->len++;
}
ser_list* FindBlock(list_header *free_header,list_header *used_header)
{
ser_list *p;
if (free_header->len < 1) {
printf("no free block!/n");
exit(0);
}
if((p = DeleteList(free_header))==NULL) {
printf("there is no block!/n");
return p;
}
AddList(used_header,(lk *)p);
return p;
}
void DeletListk(list_header* header,ser_list*p)
{
lk* q;
lk* pp;
lk* temp;
q = (lk*)p;
temp = (lk*)header;
pp=header->next;
while( (pp != q)&&(pp!=NULL)) {
temp = pp;
pp = pp->next;
}
if(pp==NULL) {
printf("Deletlistk wrong!/n");
};
temp->next = pp->next;
header->len--;
}
void ReSet(ser_list* p)
{
p->next = NULL;
p->new_fd = 0;
p->pthread = 0;
p->p_result = NULL;
p->used_flag = 0;
}
/* 从已用链表中摘除至空链表*/
void Reclaim(list_header* free_header,list_header* used_header,ser_list* p)
{
DeletListk(used_header, p);
ReSet(p);
AddList(free_header,(lk*)p);
}
server.c
#include "head.h"
void *Server_function(void *arg) ;
void *S_function(void *arg);
void SendFunction(int *p);
ssize_t package_recv(int s ,void *buf,size_t len,int flags)
{
ssize_t nleft;
ssize_t nread;
char* ptr;
ptr = (char*)buf;
nleft = len;
while(nleft > 0) {
if((nread = recv(s,ptr,nleft,flags)) < 0) {
if(errno == EINTR)
nread = 0;
else
return -1;
} else if(nread == 0)
break;
nleft -= nread;
ptr += nread;
}
return len-nleft;
}
ssize_t package_send(int s,const void *buf,size_t len,int flags)
{
ssize_t nleft;
ssize_t nread;
char *ptr;
ptr = buf;
nleft = len;
while(nleft > 0) {
if((nread = send(s,ptr,nleft,flags)) < 0) {
if(errno == EINTR)
nread = 0;
else
return -1;
} else if(nread == 0)
break;
nleft -= nread;
ptr += nread;
}
return len-nleft;
}
int time_to_exit = 0;
int main(int argc, char *argv[])
{
int res;
int i;
int sock_fd;
ser_list *p;
lk *p_temp;
pthread_t p_thread;
void *p_result;
lk *q;
/*广播线程*/
pthread_t S_Thread;
void *S_result;
/* 自己的地址信息 */
struct sockaddr_in my_addr;
/* 连接者的地址信息*/
struct sockaddr_in their_addr;
int sin_size;
InitHeader(&usedheader);
InitFreeList(&freeheader);
/* 这里就是我们一直强调的错误检查.如果调用 socket() 出错,则返回 */
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror( "socket");
exit(1);
}
/* 主机字节顺序 */
my_addr.sin_family = AF_INET;
/* 网络字节顺序,短整型 */
my_addr.sin_port = htons(MYPORT);
/* 将运行程序机器的IP填充入s_addr */
my_addr.sin_addr.s_addr = INADDR_ANY;
/* 将此结构的其余空间清零 */
bzero(&(my_addr.sin_zero), 8);
/* 这里是我们一直强调的错误检查!! */
if (bind(sock_fd, (struct sockaddr *)&my_addr,sizeof(struct sockaddr)) == -1) {
perror(" bind" );
exit(1);
}
/* 这里是我们一直强调的错误检查!! */
if (listen(sock_fd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
res = pthread_create(&S_Thread, NULL, S_function, NULL);
while(1) {
/* 这里是主 accept()循环 */
sin_size = sizeof(struct sockaddr_in);
p = FindBlock(&freeheader,&usedheader);
/* 这里是我们一直强调的错误检查!! */
if ((p->new_fd = accept(sock_fd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
/* 如果调用 accept()出现错误,则给出错误提示,进入下一个循环 */
perror("accept" );
continue;
}
p->used_flag = 1;
/* 服务器给出出现连接的信息 */
printf(" server: got connection from %s/n" , inet_ntoa(their_addr.sin_addr));
/* 这里将建立一个子进程来和刚刚建立的套接字进行通讯 */
res = pthread_create(&(p->pthread), NULL, Server_function, (void*)p);
if (res != 0) {
perror("Thread creation failed");
exit(EXIT_FAILURE);
}
}
res = pthread_join(S_Thread, S_result);
if(res != 0) {
perror("All Send Thread join failed");
exit(EXIT_FAILURE);
}
printf("All Send Thread joined/n");
/* 等待所有的子进程都退出 */
p_temp = usedheader.next;
do{
if(p_temp = NULL) break;
p_thread = ((ser_list *)(p_temp))->pthread;
p_result = ((ser_list *)(p_temp))->p_result;
p_temp = p_temp->next;
res = pthread_join(p_thread, p_result);
if(res != 0) {
perror("Thread join failed");
exit(EXIT_FAILURE);
}
printf("Thread joined/n");
}while(p_temp != NULL);
return 0;
}
/*线程服务函数*/
void *Server_function(void *arg)
{
/* 这里就是我们说的错误检查!*/
int numbytes;
char buf[MAXDATASIZE];
int new_fd;
new_fd = ((ser_list*)arg)->new_fd;
/*这里是子进程 */
while(1){
if((numbytes = package_recv(new_fd , (void*)buf, 10, 0)) < 0)
{
/* 如果接收数据错误,则显示错误信息并退出 */
perror("recv!/n");
exit(0);
}
buf[numbytes] = '/0';
if(buf[0]=='/0') {
printf("quite/n");
break;
}
printf("recive:%s/n",buf);
if((buf[0] == 'q' ||buf[0]=='Q') &&( buf[1] == '/0')) break;
}
/* 关闭new_fd 代表的这个套接字连接 */
close(new_fd );
Reclaim(&freeheader,&usedheader,(ser_list*)arg);
pthread_exit(0);
}
void *S_function(void *arg)
{
int numbytes;
char buf[MAXDATASIZE];
int send_fd;
lk *p;
while(1){
do{
printf("send message/n:");
scanf("%s",buf);
}while((p = usedheader.next) == NULL);
do{
while( (p!=NULL) &&(((ser_list*)p)->used_flag == 0)) {
p = p->next;
}
if(p == NULL) break;
send_fd = ((ser_list*)(p))->new_fd;
printf("new_fd:%d/n",send_fd);
if ((numbytes = package_send(send_fd,buf,strlen(buf),0)) == -1) {
perror("send");
close(*(int*)arg);
exit(0);
}
if((buf[0] == 'q' ||buf[0]=='Q') &&( buf[1] == '/0')) break;
p=p->next;
}while(p != NULL);
}
}