基于SOCKET简单通信程序

本文介绍了一个基于C/S模式的客服系统实现方案,通过多线程处理客户端请求,支持多客服机与主机间的通信。系统使用Linux环境下的socket编程,并详细展示了服务器端的初始化、监听、接受连接请求及线程处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要功能:利用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);
 }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值