并发服务器设计 Tcp/

服务器端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <netdb.h>
#include <pthread.h>

/*线程执行函数的读写*/
void *thr_fn(void *arg)
 {
  int size,j;
  char recv_buf[1024];
  int *parg=(int*)arg;
  int new_fd=*parg;
  printf("new_fd=%d \n",new_fd);
  while((size=read(new_fd,recv_buf,1024))>0)
    {
      if(recv_buf[0]=='@')
        break;
      printf("Message from client (%d):%s \n",size,recv_buf);
      for(j=0;j<size;j++)
        recv_buf[j]=toupper(recv_buf[j]);//转换为大写英文字母
        write(new_fd,recv_buf,size);
       memset(recv_buf,0,sizeof(recv_buf));
      }
    close(new_fd);
    return 0;
   }
   int main(int argc,char **argv)
  {
      socklen_t clt_addr_len;//  数据类型"socklen_t"和int应该具有相同的长度.
      int listen_fd;
      int com_fd;
      int ret;
      int i;
     //static char recv_buf[1024];//???
     int len;
     int port;
     pthread_t tid;
    
     struct sockaddr_in clt_addr;
     struct sockaddr_in srv_addr;
     /*服务器端运行时要给出端口信息,即监听端口*/
     if(argc!=2)
     {
       printf("Usage:%s port \n",argv[0]);
       return 1;
     }
    /*获得输入的端口*/
    port=atoi(argv[1]);//功 能: 把字符串转换成整型数.名字来源:array to integer 的缩写
    /*创建套接字用于服务器的监听*/
   listen_fd=socket(PF_INET,SOCK_STREAM,0);
   if(listen_fd<0)
   {
    perror("cannot create listening socket");
    return 1;
  }
  /*填充服务器端套节字*/
  memset(&srv_addr,0,sizeof(srv_addr));
  srv_addr.sin_family=AF_INET;
  srv_addr.sin_addr.s_addr=htonl(INADDR_ANY);//??
  srv_addr.sin_port=htons(port);
/*绑定listen_fd*/
  ret=bind(listen_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
  if(ret==-1)
  {
    perror("cannot listen the client connect request ");
    return 1; 
  }
   /*监听指定端口,连接5个客户端*/
   ret=listen(listen_fd,5);
   if(ret==-1)
    { 
      perror("cannot listen the client connect request");
      close(listen_fd);
      return 1; 
    }
  /*对每个连接来的客户端创建一个线程,单独与其通信*/
  while(1)
 {
   len=sizeof(clt_addr);
   com_fd=accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
   if(com_fd<0)
  {
      if(errno==EINTR)// 由于信号中断返回
      {
         continue;
      }
       else
     {
       perror("cannot accept client connect request");
       close(listen_fd);
        return 1;
     }
  }
    printf("com_fd=%d \n",com_fd);
    if((pthread_create(&tid,NULL,thr_fn,&com_fd))==-1)
    {
      perror("pthread_create error");
      close(listen_fd);
      close(com_fd);
      return 1;
   }
 }

    
return 0;
 }

/*
AF 表示ADDRESS FAMILY 地址族
PF 表示PROTOCOL FAMILY 协议族 
*/
/*
C类型字符串 后面有一个 '\0 ' 作为 结尾标示符隐含加入。
sizeof(a) 就包括了 '\0 '
而strlen(a) 没有将 '\0 '计算在内。 
*/
/*
in_addr_t inet_addr(const char* strptr);
  返回:若字符串有效则为32位二进制网络字节序的IPV4地址,否则为INADDR_NONE
  struct in_addr{
  in_addr_t s_addr;
  }
*/
客户端:

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netdb.h>
#include <unistd.h>

int main(int argc,int *argv[])
{
  int connect_fd;
  int ret;
  char snd_buf[1024];
  int i;
  int port;
  int len;
  static struct sockaddr_in srv_addr; //??
  if(argc!=3)
  {
   perror("Usage: lack of arguments");
   return 1;
  }
  /*获得输入端口*/
  port=atoi(argv[2]);
  /*创建套节字用于客户端的连接*/
  connect_fd=socket(PF_INET,SOCK_STREAM,0);
  if(connect_fd<0)
  {
   perror("cannot create communication socket");
   return 1;
  }
  /*填充服务器的套节字*/
 memset(&srv_addr,0,sizeof(srv_addr));
 srv_addr.sin_family=AF_INET;
 srv_addr.sin_addr.s_addr=inet_addr(argv[1]);//??32位的地址,
 srv_addr.sin_port=htons(port);

/*连接指定的服务器*/
  ret=connect(connect_fd,(struct sockaddr*)&srv_addr,sizeof(srv_addr));
  if(ret==-1)
  {
   perror("cannot connect to the server");
   close(connect_fd);
   return 1;
  }

  memset(snd_buf,0,1024);
  /*向服务器发送,读取服务器发来的消息*/
  while(1)
  {
   write(STDOUT_FILENO,"input message:",14);
   memset(snd_buf,0,sizeof(snd_buf));//?
   len=read(STDIN_FILENO,snd_buf,1024);
   if(len>0)
     write(connect_fd,snd_buf,len);
   len=read(connect_fd,snd_buf,len);
   if(len>0)
     printf("Message from server:%s ",snd_buf);
     
    if(snd_buf[0]=='@')
      break;
  }
    close(connect_fd);
   return 0;
}

注:当有客户连接时,服务器端为每个连接创建一个线程进行读写。

qust@qust-K42JZ:~/test$ gcc server_thread.c -o server_thread -lpthread
qust@qust-K42JZ:~/test$ ./server_thread 3334
cannot listen the client connect request : Address already in use
qust@qust-K42JZ:~/test$ ./server_thread 3333


qust@qust-K42JZ:~/test$ ./client_thread 211.87.147.61 3333
input message:ggggggggggggg
Message from server:GGGGGGGGGGGGG





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值