久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3615|回復: 1
打印 上一主題 下一主題
收起左側

局域網MiNi QQ完成 C語言

[復制鏈接]
跳轉到指定樓層
樓主
ID:108615 發表于 2016-3-13 18:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
      靠,終于將         青春版MiNi     QQ項目完成!利用網絡編程,客戶和服務器是TCP協議,客戶和客戶聊天使用的事UDP協議!
  

客戶端:
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <arpa/inet.h>
  6. #include <netdb.h>
  7. #include <string.h>
  8. #include <unistd.h>
  9. #include <stdlib.h>
  10. #include <sys/wait.h>
  11. #include <sys/stat.h>
  12. #include <errno.h>
  13. #include <pthread.h>
  14. /*******************************************************************************************************************/
  15. #define CLIENT_LOGIN     10                                                                                //登錄
  16. #define CLIENT_ZHUCE     20                                                                                //注冊
  17. #define EXIT                           30                                                                               //退出
  18. /*******************************************************************************************************************/
  19. typedef struct onlineclient                                                                        //在線用戶的結構體
  20. {
  21.         unsigned char onuser[6];                                                                        //在線用戶的名字       
  22.         unsigned char onip[16];                                                                        //在線用戶的ip
  23.         uint16_t onport;                                                                                //在線用戶的port
  24.         int onfd;                                                                                                //登錄成功的套接字
  25.         int count;                                                                                                //心跳的計數器
  26.         struct onlineclient *onnext;               
  27. }onclient,*onuser;
  28. typedef struct ondata                                                                                //客戶端的在線客戶結構體
  29. {
  30.         unsigned char onname[6];                       
  31.         unsigned char fip[16];
  32.         uint16_t fonport;
  33.         struct ondata *fnext;
  34. }friendlink,*flink;
  35. /*******************************************************************************************************************/
  36. unsigned char IP[16] = {0};                                                                //將自己的ip設置為全局變量
  37. uint16_t PORT = 0;                                                                                //將自己的port設置為全局變量
  38. /*******************************************************************************************************************/
  39. int select_printf();                                                                                //主界面的打印程序聲明
  40. int getname_max(unsigned char *p, unsigned int maxlen);                //獲取名字的程序聲明
  41. int getpsword_max(unsigned char *p, unsigned int maxlen);            //獲取密碼的程序聲明
  42. int client_login(int fd);                                                                        //登錄程序的聲明
  43. int client_zhuce(int fd);                                                                        //注冊程序的聲明
  44. void heatbeat(int fd);                                                                         //心跳程序的聲明
  45. flink add_friend(unsigned char *friend,flink fhead);//將信登錄的客戶添加到連表中
  46. void free_friend_on(flink fhead);                                                        //釋放舊的在線客戶連表
  47. void print_friend(flink fhead);                                                                //打印在線客戶連表
  48. /*******************************************************************************************************************/
  49. int main()                                                                                                        //客戶端主程序
  50. {
  51.    int ret = 0,fd = 0,maxfd = 0,nfound,fnameback,fnamecount = 2;
  52.    struct sockaddr_in servaddr;
  53.         struct sockaddr_in  cliaddr;                                                                //UDP
  54.         int uret;
  55.         fd_set rset,set,urset ,uset;                                                               //UDP
  56.         int umaxfd,unfound;                                                                                //UDP
  57.         unsigned char ubuf[250] = {0};                                                        //UDP
  58.         unsigned char buf[250] = {0};
  59.         unsigned char head[2] = {0};
  60.         unsigned char datalen = 0;
  61.         unsigned char friend[24] = {0};
  62.         unsigned char name[6] = {0};
  63.         unsigned char ip[16] = {0};
  64.         unsigned char buffriend[6] = {0};
  65.         int headdata = 0,readback = 0,i;
  66.         unsigned char pack_len = 0;
  67.         unsigned char *fp = NULL;
  68.         flink fhead = NULL,pp = NULL;
  69.         int fj = 0,back = 0;
  70.         uint16_t port = 0;
  71.         int sockfd,myip = 0;                                           //UDP
  72.         pthread_t heatbeatid,pthread;
  73.         int pthread_ret;
  74.         int heat_beat = 0;
  75.    fd = socket(AF_INET,SOCK_STREAM,0);
  76.    memset(&servaddr,0,sizeof(servaddr));
  77.    servaddr.sin_family=        AF_INET;
  78.    servaddr.sin_port=htons(20000);
  79.    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr.s_addr);
  80.    ret = connect(fd,(struct sockaddr*)&servaddr,sizeof(servaddr));            //三次握手
  81.    if(ret <0)
  82.            {
  83.      perror("connect");
  84.      return 1;
  85.           }
  86.         while(1)
  87.         {
  88.                         int select = 1;
  89.                         select = select_printf();                                                            //打印主界面
  90.                         switch(select)
  91.                         {
  92.                                 case CLIENT_LOGIN:select = client_login(fd);
  93.                                 break;                                                                                //選擇登錄
  94.                                 case CLIENT_ZHUCE:select = client_zhuce(fd);
  95.                                 break;                                                                                //選擇注冊
  96.                                 case EXIT:                        exit(0);
  97.                                 break;                                                                                //選擇退出
  98.                         }
  99.                         readback = read(fd,head,2);                                //提取頭
  100.                         if(readback == -1)
  101.                         {
  102.                                 printf("read head error\n");
  103.                         }
  104.                         headdata = head[0] + head[1]*256;
  105.                         readback = read(fd,&datalen,1);                        //提取數據的長度
  106.                         printf("datalen is %d\n",datalen);
  107.                         if(readback == -1)
  108.                         {
  109.                                 printf("datalen read error\n");
  110.                         }
  111.                         readback = read(fd,buf,datalen);                        //提取所有的數據
  112.                         if(readback == -1)
  113.                         {
  114.                                 printf("read data error\n");
  115.                         }
  116.                         switch(headdata)
  117.                         {
  118.                                 case 1000:if(buf[0] == 1)
  119.                                                           {
  120.                                                                 printf(" 登錄成功 \n");
  121.                                                                 memcpy(IP,&buf[1],16);                        //被設置為全局變量
  122.                                                                 printf("IP is %s\n",IP);
  123.                                                                 PORT = buf[17] + buf[18]*256;
  124.                                                                 printf("PORT is %d\n",PORT);  //被設置為全局變量
  125.                                                 heat_beat = pthread_create(&heatbeatid,NULL,(void *)heatbeat,(void *)fd);
  126.                                                                 if(heat_beat != 0)                                //此線程建立心跳
  127.                                                                 {
  128.                                                                         printf("heatbeat pthread create fail\n");
  129.                                                                         exit(1);
  130.                                                                 }
  131.                                                                 goto readserver;
  132.                                                           }
  133.                                                         else
  134.                                                           {
  135.                                                                 printf("登錄失敗\n");
  136.                                                            }
  137.                                 break;
  138.                                 case 1001:if(buf[0] == 1)
  139.                                                           {
  140.                                                                 printf(" 注冊成功 \n");
  141.                                                           }
  142.                                                         else
  143.                                                          {
  144.                                                                 printf("注冊失敗\n");
  145.                                                            }
  146.                                 break;
  147.                                 case 1004:printf(" 網絡出錯,請重新發送 \n");                                       
  148.                                 break;
  149.                         }
  150.         }
  151. /******************************************************獲得在線連表*************************************************/
  152. readserver:                                                                                        //使用goto到達這里
  153.         maxfd = fileno(stdin);
  154.         FD_ZERO(&set);                                                                        //將關注的集合清零
  155.         FD_SET(fd,&set);                                                                        //將套接字加入關注集合
  156.         FD_SET(maxfd,&set);                                                                //將鍵盤加入關注集合
  157.         maxfd = (maxfd > fd ? maxfd : fd) + 1;                                        //提取掃描的范圍
  158.         while(1)
  159.         {
  160.                 rset = set;                                                                                //將關注集合備份
  161.                 if((nfound = select(maxfd,&rset,(fd_set *)0,(fd_set*)0,NULL)) < 0)
  162.                 {                                                                                                //掃描關注集合
  163.                         if(errno == EINTR)
  164.                         {
  165.                                 fprintf(stderr,"interrupted system call\n");
  166.                                 continue;
  167.                         }
  168.                         perror("select");
  169.                         exit(1);
  170.                 }
  171.                 if(FD_ISSET(fd,&rset))                                                        //測試sock是否有變化
  172.                 {
  173.                         readback = read(fd,head,2);                                        //讀出頭文件
  174.                         readback = read(fd,&datalen,1);                                //讀出長度
  175.                         readback = read(fd,buf,datalen);                                //讀出所有的數據
  176.                         headdata = head[0] + head[1]*256;
  177.                         if(headdata == 1003)
  178.                         {
  179.                                 pack_len = buf[0];                                                //提取總的節點的長度
  180.                                 free_friend_on(fhead);                                        //每次建立連表的時候先釋放以前的連表
  181.                                 for(i = 0;i < pack_len;i++)                                        //循環每個節點
  182.                                 {
  183.                                         memset(friend,0,24);                                //清零
  184.                                         memcpy(friend,&buf[1+24*i],24);                //提取解點
  185.                                         fhead = add_friend(friend,fhead);            //建立在線客戶的連表
  186.                                 }
  187.                                 print_friend(fhead);
  188.                                 printf("請輸入你要聊天的朋友姓名\n");
  189.                         }
  190.                         else
  191.                         {
  192.                                 continue;                                                                //收到的heddata不是1003就從新掃描
  193.                         }
  194.                 }
  195.                 if(FD_ISSET(fileno(stdin),&rset))
  196.                 {
  197.                         memset(buffriend,0,sizeof(buffriend));                //將name數組清零
  198.                         fnameback = getname_max(buffriend, 6);        //判斷名字是否符合要求,并取得名字(小于  4  個字節)
  199.                         while(fnameback == -1)
  200.                         {
  201.                                 memset(buffriend,0,sizeof(buffriend));        //將name數組清零
  202.                                 printf("請重新輸入你的姓名,至多還輸入  %d\n",fnamecount);
  203.                                 fnameback = getname_max(buffriend, 6);
  204.                                 printf("fnameback is %d\n",fnameback);
  205.                                 if(fnameback == -1)
  206.                                 {
  207.                                         fnamecount--;                                        //登錄時輸入姓名錯誤計數器減 1
  208.                                 }
  209.                                 if(fnameback == 1)
  210.                                 {
  211.                                         break;                                                        //登錄時輸入姓名正確退出循環
  212.                                 }
  213.                                 if(fnamecount == 0)
  214.                                 {
  215.                                         exit(0);                                                        //登錄時輸入錯誤超過三次自動退出
  216.                                 }
  217.                         }
  218.                         fp = buffriend;
  219.                         fj = 0;
  220.                         while(*fp != '\n')                                //將   \n  轉換為     \0      因此讀取數組的長度
  221.                         {
  222.                                 fj++;
  223.                                 fp++;
  224.                         }
  225.                         buffriend[fj] = '\0';                                                         //將最后面的\n賦值為\0
  226.                         pp = fhead;
  227.                         while(pp != NULL)
  228.                         {
  229.                                 if((back =strcmp((pp->onname),buffriend)) == 0)//對比連表查找ip 和 port
  230.                                 {
  231.                                         break;                                                        //找到ip 和  port 退出
  232.                                 }
  233.                                 pp = pp->fnext;                                                  //指向下一個節點
  234.                         }
  235.                         if(pp != NULL)
  236.                         {
  237.                                 break;                                                                //如果找到就跳出循環
  238.                         }
  239.                 }               
  240.         }
  241.         printf("friend pp->onname is %s\n",(pp->onname));//打印聊天朋友的名字
  242.         printf("friend pp->fonport is %d\n",(pp->fonport));//打印聊天朋友的port
  243. /*********************************************開始UDP通信*************************************************/
  244.         if((sockfd = socket(AF_INET,SOCK_DGRAM,0)) < 0)//建立udp套接字
  245.         {
  246.                 perror("error opening socket\n");
  247.                 return -1;
  248.         }
  249.         memset(&cliaddr,0,sizeof(cliaddr));
  250.         cliaddr.sin_family = AF_INET;                                                        //賦值地址族
  251.         printf("my port is %s\n",IP);
  252.         myip = inet_pton(AF_INET,IP,&cliaddr.sin_addr.s_addr);        //賦值ip
  253.         printf("my port is %d\n",PORT);
  254.         cliaddr.sin_port = htons(PORT);                                                 //賦值port
  255.         if((uret = bind(sockfd,(struct sockaddr *)&cliaddr,sizeof(cliaddr))) < 0)
  256.         {                                                                                                //邦定ip  和   port
  257.                 perror("error on binging");
  258.                 close(sockfd);
  259.         }
  260.         memset(&cliaddr,0,sizeof(cliaddr));
  261.         cliaddr.sin_family = AF_INET;                                                        //賦值需要連接的地址族
  262.         printf("pp->fip is %s\n",pp->fip);
  263.         myip = inet_pton(AF_INET,(pp->fip),&cliaddr.sin_addr.s_addr);
  264.         printf("pp->fonport is %d\n",pp->fonport);
  265.         cliaddr.sin_port = htons(pp->fonport) ;                                   //邦定需要連接ip  和   port
  266.         umaxfd = fileno(stdin);
  267.         FD_ZERO(&uset);                                                                      //關注集合清零
  268.         FD_SET(sockfd,&uset);                                                              //udp套接字加入關注集合
  269.         FD_SET(umaxfd,&uset);                                                              //鍵盤輸入也加入關注的集合
  270.         umaxfd = (umaxfd > sockfd ? umaxfd : sockfd) + 1;                 //找出最大的掃描量
  271.         while(1)
  272.         {
  273.                 urset = uset;                                                                   //備份關注集合
  274.                 if((unfound = select(umaxfd,&urset,(fd_set*)0,(fd_set*)0,NULL)) < 0)
  275.                 {                                                                                         //沒有變化就阻塞
  276.                         if(errno == EINTR)
  277.                         {
  278.                                 fprintf(stderr,"interrupted system call\n");
  279.                                 continue;
  280.                         }
  281.                         perror("select");
  282.                         exit(1);
  283.                 }
  284.                 if(FD_ISSET(fileno(stdin),&urset))                                //檢測鍵盤是否有輸入
  285.                 {
  286.                         memset(ubuf,0,sizeof(ubuf));
  287.                         system("date");
  288.                         printf("請輸入你的聊天內容~~~~~~~");
  289.                         if(fgets(ubuf,sizeof(ubuf)-1,stdin) == NULL)            //獲得你的輸入
  290.                         {
  291.                                 if(ferror(stdin))
  292.                                 {
  293.                                         perror("stdin");
  294.                                         break;
  295.                                 }
  296.                         }
  297.                         ret = strlen(ubuf);
  298.                         ubuf[ret-1] = '\0';
  299.                         if((ret = sendto(sockfd,ubuf,strlen(ubuf),0,(struct sockaddr*)&cliaddr,sizeof(cliaddr))) < 0)                                                        //發送給好友
  300.                         {
  301.                                 perror("ERROR writing to UDP socket");
  302.                                 break;
  303.                         }
  304.                 }
  305.                 if(FD_ISSET(sockfd,&urset))                                            //檢測好友有沒有發送東西過來
  306.                 {
  307.                         uint32_t length = sizeof(cliaddr);
  308.                         memset(ubuf,0,sizeof(ubuf));
  309.                         if((ret = recvfrom(sockfd,ubuf,sizeof(ubuf)-1,0,(struct sockaddr*)&cliaddr,&length)) < 0)                                        //接受好友發過來的信息
  310.                         {
  311.                                 perror("ERROR reading from UDP socket");
  312.                                 break;
  313.                         }
  314.                         ubuf[ret] = 0;                                                        //將最后的賦值為\n
  315.                         system("date");
  316.                         printf("你接受的內容是 :%s\n",ubuf);
  317.                 }
  318.                
  319.         }
  320.         close(sockfd);                                                                            //關閉套接字
  321.         close(fd);
  322. }
  323. /************************************************************************************************************/
  324. void print_friend(flink fhead)                                                            //打印朋友連表的程序
  325. {
  326.         flink p = fhead;
  327.         while(p != NULL)
  328.         {
  329.                 printf("ip is %s\n",(p->fip));
  330.                 printf("port is %d\n",(p->fonport));
  331.                 printf("name is %s\n",(p->onname));
  332.                 p = p->fnext;
  333.         }
  334. }
  335. /************************************************************************************************************/
  336. void free_friend_on(flink fhead)                                                    //防止內存泄露  釋放節點的程序
  337. {
  338.         flink p = fhead;
  339.         while(fhead != NULL)
  340.         {
  341.                 p = fhead;
  342.                 fhead = p->fnext;
  343.                 free(p);
  344.         }
  345. }
  346. /************************************************************************************************************/
  347. flink add_friend(unsigned char *friend,flink fhead)
  348. {                                                        //服務器端發過來的新的在線客戶,將新的在線客戶添加到連表
  349.         flink p = fhead,s = NULL,tail = NULL;
  350.         s = (flink)malloc(sizeof(friendlink));//malloc新的空間
  351.         if(s == NULL)
  352.         {
  353.                 printf("malloc fail\n");                                              //創建失敗直接返回首地址
  354.                 return fhead;
  355.         }
  356.         memcpy((s->fip),friend,16);                                              //提取朋友的ip
  357.         s->fonport = friend[16] + friend[17] * 256;//提取朋友的port
  358.         memcpy((s->onname),&friend[18],6);                             //提取朋友的姓名
  359.         if(fhead == NULL)
  360.         {
  361.                 fhead = s;
  362.                 fhead->fnext = NULL;
  363.         }
  364.         else
  365.         {
  366.                 while(p != NULL)
  367.                 {
  368.                         tail = p;
  369.                         p = p->fnext;
  370.                 }
  371.                 tail->fnext = s;
  372.                 s->fnext = NULL;
  373.         }
  374.         return fhead;                                                                                //返回首地址
  375. }
  376. /*****************************************下面是心跳線程程序****************************************/
  377. void heatbeat(int fd)
  378. {
  379.         unsigned char buf[250] = {0};
  380.         int writeback = 0;
  381.         buf[0]=1002%256;                //心跳的head  是 1002
  382.         buf[1]=1002/256;
  383.         buf[2]=1;                                //數據長度是  1
  384.         buf[3]=1;                                //發給服務器的是數據是    1
  385.         while(1)
  386.         {
  387.                 writeback = write(fd,buf,4);
  388.                 if(writeback == -1)
  389.                 {
  390.                         printf("heart beat write fail\n ");
  391.                 }
  392.                 sleep(3);                //每隔    3  秒發送  一個  1     給服務器
  393.         }
  394. }
  395. /****************************************下面主界面的打印程序***************************************/
  396. int select_printf()
  397. {
  398.         int select;                                                                                       
  399.         printf("\t\t\t\t 1.登錄 \t\t\n");
  400.         printf("\t\t\t\t 2.注冊 \t\t\n");
  401.         printf("\t\t\t\t 3.退出 \t\t\n");
  402.         scanf("%d",&select);
  403.         getchar();
  404.         //while(getchar()!='\n')
  405.         while(select < 1||select > 3)
  406.         {
  407.                 system("clear");
  408.                 printf("\t\t\t輸入錯誤請重新輸入\t\t\n");
  409.                 printf("\t\t\t\t 1.登錄 \t\t\n");
  410.                 printf("\t\t\t\t 2.注冊 \t\t\n");
  411.                 printf("\t\t\t\t 3.退出 \t\t\n");
  412.                 scanf("%d",&select);
  413.                 getchar();
  414.         }
  415.         select = select*10;
  416.         return select ;
  417. }
  418. /*******************************************下面是獲取名字的程序**************************************************/
  419. int getname_max(unsigned char *p, unsigned int maxlen)        //最多接受字符串maxlen-2
  420. {
  421.         unsigned char *q = p;
  422.         unsigned int counter = 0;                                        //輸入字符的計數器
  423.         while (1)
  424.         {
  425.                 *q = getchar();                                                        //逐個取出緩存中的輸入
  426.                 counter ++;
  427.                 if (counter >= maxlen)                                        //當counter > maxlen時  將所有的輸入清零
  428.                 {
  429.                         if(*q == '\n')
  430.                         {
  431.                                 memset(p, 0, maxlen);                        //清空剛才接受的字符數組
  432.                                 return -1;
  433.                         }
  434.                         if(*q != '\n')                                                //當counter >> maxlen是輸入的   \n 將所有的輸入清零
  435.                         {
  436.                                 while (getchar() != '\n');                        //把剩下的接受完
  437.                                 memset(p, 0, maxlen);                        //清空剛才接受的字符數組
  438.                                 return -1;
  439.                         }
  440.                 }
  441.                 if (*q == '\n')                                                        //counter < maxlen 當接受到     時就返回   1
  442.                 {
  443.                         return 1;                                                        //返回  1
  444.                 }
  445.                 else
  446.                 {
  447.                         q ++;                                                        //將指針 q 移到下一個位子
  448.                 }
  449.         }
  450. }
  451. /*****************************************下面是獲取密碼的程序*********************************************/
  452. int getpsword_max(unsigned char *p, unsigned int maxlen)        //最多接受字符串maxlen-2
  453. {
  454.         unsigned char *q = p;
  455.         unsigned int counter = 0;                                                    //輸入字符的計數器
  456.         while (1)
  457.         {
  458.                 *q = getchar();                                                            //逐個取出緩存中的輸入
  459.                 counter ++;
  460.                 if (counter >= maxlen)                                            //當counter > maxlen時  將所有的輸入清零
  461.                 {
  462.                         if(*q == '\n')                                                    //maxlen是輸入的   \n 將所有的輸入清零
  463.                         {
  464.                                 memset(p, 0, maxlen);                          //清空剛才接受的字符數組
  465.                                 return -1;
  466.                         }  
  467.                         if(*q != '\n')                //當counter >> maxlen是輸入的   \n 將所有的輸入清零
  468.                         {
  469.                                 while (getchar() != '\n');                          //把剩下的接受完
  470.                                 memset(p, 0, maxlen);                          //清空剛才接受的字符數組
  471.                                 return -1;                                                    //返回   -1
  472.                         }
  473.                 }
  474.                 if (*q == '\n')                                                        //counter < maxlen 當接受到     時就返回   1
  475.                 {
  476.                         return 1;                                                        //返回  1
  477.                 }
  478.                 else
  479.                 {
  480.                         q ++;                                                        //將指針 q 移到下一個位子
  481.                 }
  482.         }
  483. }
  484. /****************************************下面是客戶登錄的程序************************************************/
  485. int client_login(int fd)                                                                                //客戶登錄的程序
  486. {
  487.         unsigned char buf[250] = {0};
  488.         unsigned char name[6] ={0};                        //獲得名字的字符數組 最多輸入  5   個字符
  489.         unsigned char psword[4] = {0};                //獲得密碼的字符數組 最多輸入  3    個字符
  490.         int nameback = 0,        pswordback = 0;
  491.         int namecount = 2,pswordcount = 2;
  492.         int namelen = 0,        pswordlen = 0;
  493.         int writeback = 0,readback = 0;
  494.         unsigned char *p = NULL;
  495.         int j = 0;
  496.         buf[0]=1000%256;
  497.         buf[1]=1000/256;
  498.         printf("請輸入你的姓名(小于  4  個字節)至多3次\n");
  499.         memset(name,0,sizeof(name));                                 //將name數組清零
  500.         nameback = getname_max(name, 6);        //判斷名字是否符合要求,并取得名字(小于  4  個字節)
  501.         while(nameback == -1)
  502.         {
  503.                 memset(name,0,sizeof(name));                        //將name數組清零
  504.                 printf("請重新輸入你的姓名,至多還輸入  %d\n",namecount);
  505.                 nameback = getname_max(name, 6);
  506.                 if(nameback == -1)
  507.                 {
  508.                         namecount--;                                                //登錄時輸入姓名錯誤計數器減 1
  509.                 }
  510.                 if(nameback == 1)
  511.                 {
  512.                         break;                                                        //登錄時輸入姓名正確退出循環
  513.                 }
  514.                 if(namecount == 0)
  515.                 {
  516.                         exit(0);                                                        //登錄時輸入錯誤超過三次自動退出
  517.                 }
  518.         }
  519.         //namelen = strlen(name);//獲取密碼的長度(不能使用strlen的去長度  psword 遇到\0 就結束)
  520.         p = name;
  521.         j = 0;
  522.         while(*p != '\n')                                                                //將   \n  轉換為     \0      因此讀取數組的長度
  523.         {
  524.                 j++;
  525.                 p++;
  526.         }
  527.         name[j] = '\0';                                                             //將最后面的\n賦值為\0
  528.         buf[2] = 10;
  529.         memcpy(&buf[3],name,6);
  530. /*------------------------------------------------------------------名字取得完畢*/
  531.         memset(psword,0,sizeof(psword));                //將psword數組清零
  532.         printf("請輸入你的密碼(小于  3  個字節)至多3次\n");
  533.         pswordback = getpsword_max(psword,4);//判斷密碼是否符合要求,并取得密碼(小于  3  個字節)
  534.         while(pswordback == -1)
  535.         {
  536.                 memset(psword,0,sizeof(psword));        //將psword數組清零
  537.                 printf("請重新輸入你的密碼,至多還輸入  %d\n",namecount);
  538.                 pswordback = getpsword_max(psword,4);
  539.                 if(pswordback == -1)
  540.                 {
  541.                         pswordcount--;                                                        //密碼輸入錯誤計數器減 1
  542.                 }
  543.                 if(pswordback == 1)
  544.                 {
  545.                         break;                                                                //密碼輸入正確退出while語句
  546.                 }
  547.                 if(pswordcount == 0)
  548.                 {
  549.                         exit(0);                                                                //密碼輸入錯誤超過三次自動退出
  550.                 }
  551.         }
  552.         //pswordlen = strlen(psword);//獲取密碼的長度(不能使用strlen的去長度  psword 遇到 \0  就結束)
  553.         p = psword;
  554.         j = 0;
  555.         while(*p!='\n')                                                        //將   \n  轉換為     \0      因此讀取數組的長度
  556.         {
  557.                 j++;
  558.                 p++;
  559.         }
  560.         psword[j] = '\0';                                                        //將最后面的  \n  賦值為     \0
  561.         memcpy(&buf[9],psword,4);                                //將密碼賦值給以地址buf[13]開頭的地址
  562. /*-------------------------------------------------------------密碼取得完畢*/
  563.         writeback = write(fd,buf,13);
  564.         if(writeback == -1)
  565.         {
  566.                 printf("write error\n");
  567.                 return 1;
  568.         }
  569. }
  570. /****************************************下面是客戶注冊的程序************************************************/
  571. int client_zhuce(int fd)                                                        //客戶端的注冊程序
  572. {
  573.         unsigned char buf[250] = {0};
  574.         unsigned char name[6] ={0};
  575.         unsigned char psword[4] = {0};
  576.         int nameback = 0,pswordback = 0;
  577.         int namecount = 2,pswordcount = 2;
  578.         int namelen = 0,pswordlen = 0;
  579.         unsigned char len = 2;
  580.         int j = 0;
  581.         int writeback = 0,readback = 0;
  582.         int cmpback = 3;
  583.         unsigned char *p = NULL;
  584.         memset(buf,0,250);
  585.         buf[0]=1001%256;
  586.         buf[1]=1001/256;
  587.         memset(name,0,sizeof(name));                                //將name數組清零
  588.         printf("請輸入你的姓名(小于   5  字節)至多3次\n");
  589.         nameback = getname_max(name, 6);//判斷名字是否符合要求,并取得名字(小于   5  字節)
  590.         while(nameback == -1)
  591.         {
  592.                 memset(name,0,sizeof(name));                        //將name數組清零
  593.                 printf("請重新輸入你的姓名,至多還輸入  %d\n",namecount);
  594.                 nameback = getname_max(name, 6);

  595.                 if(nameback == -1)
  596.                 {
  597.                         namecount--;                                        //輸入的姓名不符合規定計數器減 1
  598.                 }
  599.                 if(nameback == 1)
  600.                 {
  601.                         break;                                                //輸入的姓名正確退出循環
  602.                 }
  603.                 if(namecount == 0)
  604.                 {
  605.                         exit(0);                                                //輸入姓名的次數超過三次退出
  606.                 }
  607.         }
  608.         //namelen = strlen(name);//獲取密碼的長度(不能使用strlen的去長度  psword 遇到  \0    就結束)
  609.         p = name;
  610.         while(*p != '\n')                                        //將   \n  轉換為     \0      因此讀取數組的長度
  611.         {
  612.                 j++;
  613.                 p++;
  614.         }
  615.         name[j] = '\0';                                                               //將最后面的\n賦值為\0
  616.         buf[2] = 10;
  617.         memcpy(&buf[3],name,6);
  618. /*------------------------------------------------------名字取得完畢*/
  619.         memset(psword,0,sizeof(psword));                                //將psword數組清零
  620.         printf("請輸入你的密碼(小于3個字符)\n");
  621.         pswordback = getpsword_max(psword,4);                //判斷密碼是否符合要求,并取得密碼(小于3個字符)
  622.         while(pswordback == -1)
  623.         {
  624.                 memset(psword,0,sizeof(psword));                        //將psword數組清零
  625.                 printf("請重新輸入你的密碼,至多還輸入  %d\n",namecount);
  626.                 pswordback = getpsword_max(psword,4);
  627.                 if(pswordback == -1)
  628.                 {
  629.                         pswordcount--;                                                        //輸入的密碼不符合規定計數器減 1
  630.                 }
  631.                 if(pswordback == 1)
  632.                 {
  633.                         break;                                                                //輸入的密碼正確退出循環
  634.                 }
  635.                 if(pswordcount == 0)
  636.                 {
  637.                         exit(0);                                                                //輸入密碼的次數超過三次退出
  638.                 }
  639.         }
  640.         //pswordlen = strlen(psword);//獲取密碼的長度(不能使用strlen的去長度  psword 遇到  \0    就結束)
  641.         p = psword;
  642.         j = 0;
  643.         while(*p!= '\n')                                                                        //將   \n  轉換為     \0      因此讀取數組的長度
  644.         {
  645.                 j++;
  646.                 p++;
  647.         }
  648.         psword[j] = '\0';                                                                        //將最后面的\n賦值為\0
  649.         memcpy(&buf[9],psword,4);                                                //將密碼賦值給以地址buf[13]開頭的地址
  650. /*--------------------------------------------------密碼取得完畢*/
  651.         writeback = write(fd,buf,13);                                                //將打包好的數據發給服務器
  652.         printf("writeback = %d\n",writeback);
  653.         if(writeback == -1)
  654.         {
  655.                 perror("error");
  656.                 return 1;
  657.         }
  658. }
  659. /********************************以上是注冊讀出服務器的返回的在線客戶連表*******************************/
復制代碼

服務器端:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdarg.h>
  6. #include <sys/types.h>
  7. #include <sys/ipc.h>
  8. #include <sys/shm.h>
  9. #include <sys/sem.h>
  10. #include <errno.h>
  11. #include <ctype.h>
  12. #include <sys/msg.h>
  13. #include <fcntl.h>
  14. #include <sys/socket.h>
  15. #include <netinet/in.h>
  16. #include <netdb.h>
  17. #include <arpa/inet.h>
  18. #include <ctype.h>
  19. #include <sys/time.h>
  20. #include <sys/select.h>
  21. /*******************************************************************************************************************/
  22. #define LISTEN_QUEUE_NUM 5                                //某一時刻可以監聽的個數
  23. #define BUFFER_SIZE      250                        //buf的大小
  24. #define ECHO_PORT        20000                //服務器的port
  25. /*******************************************************************************************************************/
  26. typedef struct client                                        //注冊的結構體
  27. {
  28.         unsigned char username[6];                        //客戶的姓名
  29.         unsigned char userpsword[4];                //客戶的密碼
  30.         struct client *next;                                        //指向注冊成功的下一個指針
  31. }clientlink,*lclientlink;
  32. typedef struct onlineclient                        //在線用戶的結構體
  33. {
  34.         unsigned char onuser[6];                        //在線用戶的名字       
  35.         unsigned char onip[16];                                //在線用戶的ip
  36.         uint16_t onport;                                                //在線用戶的port
  37.         int onfd;                                                                //登錄成功的套接字
  38.         int count;                                                                //心跳的計數器
  39.         int flag;                                                                //設計登錄的標記
  40.         struct onlineclient *onnext;                //指向下一個在線客戶的指針
  41. }onclient,*onuser;
  42. /*******************************************************************************************************************/
  43. onuser onhead = NULL;                                         //全局變量的在線客戶連表頭指針
  44. unsigned char BUFIP[16] = {0};           //獲得上線客戶端的16個字節的ip
  45. uint16_t CLIENTPORT = 0;                                 //獲得上線客戶端的2個字節的port
  46. int CLIENT_FD  = 0;                                                //登錄成功的套接字
  47. /*******************************************************************************************************************/
  48. void jiluname_psword(int fd,unsigned char *buf,unsigned char datalen);
  49. //注冊的程序
  50. void cmpname_psword(int fd,unsigned char *buf,unsigned char datalen);
  51. //登錄的程序
  52. onuser add_mes_to_onuser(unsigned char *name,int fd,onuser onhead);
  53. //將登錄完的客戶的信息補充完整
  54. void record_onuser_send(int fd,unsigned char *buf,onuser onhead);
  55. //在線客戶連表廣播給剛登錄的客戶
  56. void head_default(int fd,unsigned char *buf);
  57. //頭文件出錯的程序
  58. lclientlink read_clientlink();
  59. //打開注冊過的文件程序
  60. int save_link(lclientlink head);
  61. //保存注冊過的文件程序
  62. void add_onuser();
  63. //添加新登錄的客戶程序
  64. onuser reseach(onuser onhead,int fd);
  65. //查找剛上線的客戶程序
  66. void printfonuser(onuser onhead);
  67. //打印在線客戶連表的程序
  68. int recive_heatbeat(int fd);
  69. //接受客戶的心跳程序
  70. int scan_onlive_user();
  71. //遍歷整個在線連表程序
  72. /*******************************************************************************************************************/
  73. int main(int argc,char **argv)                                                                                //服務器的主函數
  74. {
  75.         lclientlink head = NULL;
  76.         struct sockaddr_in servaddr,remote;
  77.         int request_sock,new_sock;
  78.         int nfound,fd,maxfd,bytesread;
  79.         uint32_t addrlen;
  80.         fd_set rset,set;
  81.         struct timeval timeout;
  82.         unsigned char buf[BUFFER_SIZE] = {0};
  83.         unsigned char headdata[2] = {0};
  84.         unsigned char datalen = 0;
  85.         int headlen = 0;
  86.         pthread_t scanid;                                                                                          //初始化新的線程   ID
  87.         int scanret;
  88.         if((request_sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) < 0)
  89.         {                                                                                                                //建立套接字
  90.                 perror("socket");
  91.                 return -1;
  92.         }
  93.         memset(&servaddr,0,sizeof(servaddr));
  94.         servaddr.sin_family = AF_INET;
  95.         inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr.s_addr);
  96.         //將字符串表示的地址轉換成協議大端字符地址
  97.         servaddr.sin_port = htons((uint16_t)ECHO_PORT);//bind  port
  98.         if(bind(request_sock,(struct sockaddr*)&servaddr,sizeof(servaddr)) < 0)
  99.         {                                                                                                                   //bind套接字
  100.                 perror("bind");
  101.                 return -1;
  102.         }
  103.         if(listen(request_sock,LISTEN_QUEUE_NUM) < 0)                                      //監聽
  104.         {
  105.                 perror("listen");
  106.                 return -1;
  107.         }
  108. /*************************************掃描count刪除連表中的下線成員****************************************/
  109.         scanret = pthread_create(&scanid,NULL,(void *)scan_onlive_user,NULL);
  110.         if(scanret != 0)                                                                                            //建立掃描心跳的線程
  111.         {
  112.                 printf("creat  pthread  fail\n");
  113.                 exit(1);
  114.         }
  115. /*******************************************************************************************************************/
  116.         FD_ZERO(&set);                                                                                    //將關注集合清零
  117.         FD_SET(request_sock,&set);                                                                    //將監聽套節字置    1
  118.         maxfd = request_sock;                                                                            //將監聽套節字賦值給掃描范圍
  119.         while(1)
  120.         {
  121.                 rset = set;                                                                                            //備份關注集合
  122.                 timeout.tv_sec =0;                                                                            // 秒鐘設置為  0
  123.                 timeout.tv_usec = 500000;                                                            //設置為500000微妙掃描  1   次
  124.                 if((nfound = select(maxfd + 1,&rset,(fd_set*)0,(fd_set*)0,&timeout)) < 0)
  125.                 {
  126.                         perror("select");
  127.                         return -1;
  128.                 }
  129.                 else if(nfound == 0)
  130.                 {
  131.                         printf(".");                                                                                        //沒有人上線就打點
  132.                         fflush(stdout);                                                                                //清空緩存
  133.                         continue;
  134.                 }
  135.                 if(FD_ISSET(request_sock,&rset))
  136.                 {
  137.                         addrlen = sizeof(remote);                                                            //獲取結構體的字節數
  138.                         if((new_sock = accept(request_sock,(struct sockaddr*)&remote,&addrlen)) < 0)//
  139.                         {
  140.                                 perror("accept");
  141.                                 return -1;
  142.                         }
  143.                         printf("connection from  host %s,port %d,socket %d\r\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port),new_sock);
  144. /******************************************連接上了服務器的客戶信息****************************************/
  145.                         memcpy(BUFIP,(inet_ntoa(remote.sin_addr)),16);              //獲取上線的的ip  16
  146.                         CLIENTPORT = ntohs(remote.sin_port);                              //獲取上線的port        4
  147.                         CLIENT_FD = new_sock;                                                         //上線客戶的套接字    4
  148.                         add_onuser();                                                                          //添加客戶的信息
  149. /*******************************************以上連接上了服務器的客戶信息********************************/
  150.                         FD_SET(new_sock,&set);
  151.                         if(new_sock > maxfd)
  152.                                 maxfd = new_sock;
  153.                         FD_CLR(request_sock ,&rset);
  154.                         nfound--;       
  155.                 }
  156.                 for(fd = 0;fd <= maxfd&&nfound > 0;fd++)                        //掃描
  157.                 {
  158.                         if(FD_ISSET(fd,&rset))
  159.                         {
  160.                                 nfound--;
  161.                                 bytesread = read(fd,headdata,2);                        // 讀出文件的頭并檢測
  162.                                 if(bytesread < 0)                                                //數據讀取失敗
  163.                                 {
  164.                                         perror("read");
  165.                                 }
  166.                                 headlen = headdata[0] + headdata[1] * 256;            //解析出    頭
  167.                                 bytesread = read(fd,&datalen,1);                            //讀出文件中數據的長度并檢測
  168.                                 if(bytesread < 0)                                                    //讀取數據失敗
  169.                                 {
  170.                                         perror("read");
  171.                                 }
  172.                                 bytesread = read(fd,buf,datalen);                         //讀出文件中的數據并檢測
  173.                                 if(bytesread < 0)                                                    //讀取數據失敗
  174.                                 {
  175.                                         perror("read");
  176.                                 }
  177.                                 if(bytesread == 0)                                                    //數據讀取完畢
  178.                                 {
  179.                                         fprintf(stderr,"server :end  of file  on %d\r\n",fd);
  180.                                         FD_CLR(fd,&set);
  181.                                         close(fd);
  182.                                         continue;
  183.                                 }
  184.                                 switch(headlen)
  185.                                 {
  186.                                         case 1000:cmpname_psword(fd,buf,datalen); //登錄程序
  187.                                                 break;
  188.                                         case 1001:jiluname_psword(fd,buf,datalen);    //注冊程序
  189.                                                 break;
  190.                                         case 1002:recive_heatbeat(fd);                         //接受客戶的心跳程序
  191.                                                 break;
  192.                                         default:  head_default(fd,buf);                                 //協議頭出現錯誤程序
  193.                                                 break;
  194.                                 }
  195.                         }
  196.                 }       
  197.         }
  198.         return 0;
  199. }
  200. /************************************************************************************************************************************************/
  201. int scan_onlive_user()                                                                        //心跳程序每5秒掃描一次  
  202. {
  203.         onuser p = onhead,tail = NULL;
  204.         while(1)
  205.         {
  206.                 sleep(5);
  207.                 while(1)
  208.                 {
  209.                         p = onhead;
  210.                         if(p == NULL)
  211.                         {
  212.                                 printf("empty  onuser list\n");                                //有空連表
  213.                                 return -1;
  214.                         }       
  215.                         if((p->count) > 60)
  216.                         {
  217.                                 onhead = onhead->onnext;
  218.                         }
  219.                         else
  220.                         {
  221.                                 while((p != NULL)&&((p->count) < 60))          //少于60就刪除節點
  222.                                 {
  223.                                         tail = p;
  224.                                         p = p->onnext;
  225.                                 }
  226.                                 tail->onnext = p->onnext;
  227.                                 break;
  228.                         }
  229.                         if(p == NULL)                                                                //如果能夠掃描結束解退出循環
  230.                         {
  231.                                 break;
  232.                         }
  233.                 }
  234.                 p =onhead;
  235.                 while(p != NULL)                                                                //給計數器賦值
  236.                 {
  237.                         (p->count) = (p->count) + 5;
  238.                         p = p->onnext;
  239.                 }
  240.         }
  241. }
  242. /************************************************************************************************************************************************/
  243. int recive_heatbeat(int fd)                                                                 // 如果有在線連表中的   count  清零
  244. {
  245.         onuser p = NULL;
  246.         p = onhead;
  247.         if(p == NULL)
  248.         {
  249.                 printf("empty  onuser list\n");                                            //理論上不應該有空連表
  250.                 return -1;
  251.         }
  252.         else
  253.         {
  254.                 while(p != NULL)
  255.                 {
  256.                         if((p->onfd) == fd)                                                            //接受到心跳包 就將  該  fd 對應的計數器清零
  257.                         {
  258.                                 (p->count) = 0;                                                            //清零處理
  259.                                 printf("\n");
  260.                         }
  261.                         p = p->onnext;                                                                    //指向下一個成員
  262.                 }
  263.                
  264.         }
  265. }
  266. /************************************************************************************************************************************************/
  267. void head_default(int fd,unsigned char *buf)//head出現錯誤
  268. {
  269.         int writeback = 0;
  270.         memset(buf,0,sizeof(buf));
  271.         buf[0]=1004%256;
  272.         buf[1]=1004/256;
  273.         buf[2]= 1;
  274.         buf[3]= 2;                                                                                        //失敗返回2
  275.         writeback = write(fd,buf,strlen(buf));
  276.         if(writeback == -1)
  277.         {
  278.                 printf("write error\n");
  279.         }
  280. }
  281. /************************************************************************************************************************************************/
  282. void jiluname_psword(int fd,unsigned char *buf,unsigned char datalen)
  283. {                                                                                                            //服務器端記載注冊的人
  284.         int writeback = 0;
  285.         int saveback = 0;
  286.         lclientlink head = NULL,s = NULL;
  287.         head = read_clientlink();                                                                    //打開文件并讀文件將返回值給head
  288.         printf("buf is %s\n",buf);
  289.         saveback = add_client(head,buf);                                                //將注冊人的信息添加到連表中去
  290.         printf("saveback is %d\n",saveback);
  291.         if(saveback == -1)
  292.         {
  293.                 memset(buf,0,sizeof(buf));
  294.                 buf[0]=1001%256;
  295.                 buf[1]=1001/256;
  296.                 buf[2]= 1;
  297.                 buf[3]= 2;                                                                                    //失敗返回2
  298.                 writeback = write(fd,buf,strlen(buf));
  299.                 if(writeback == -1)
  300.                 {
  301.                         printf("write error\n");
  302.                 }
  303.         }
  304.         else
  305.         {
  306.                 memset(buf,0,sizeof(buf));
  307.                 buf[0]=1001%256;
  308.                 buf[1]=1001/256;
  309.                 buf[2]= 1;
  310.                 buf[3]= 1;                                                                                        //成功返回1
  311.                 writeback = write(fd,buf,strlen(buf));
  312.                 if(writeback == -1)
  313.                 {
  314.                         printf("write error\n");
  315.                 }
  316.         }
  317. }
  318. /************************************************************************************************************************************************/
  319. lclientlink read_clientlink()                                                                         //打開文件并讀文件
  320. {
  321.         int fid;
  322.         int read_value;
  323.         lclientlink head = NULL,s = NULL,tail = NULL;
  324.         fid = open("client.ini",O_RDONLY);
  325.         if(fid == -1)
  326.         {
  327.                 printf("open error\n");
  328.                 //return -1;                                                                                //打開文件失敗返回-1
  329.         }
  330.         s = (lclientlink)malloc(sizeof(clientlink));
  331.         while(read_value = read(fid,s,sizeof(clientlink)) != 0)
  332.         {
  333.                 if(head == NULL)
  334.                 {
  335.                         head = s;
  336.                         tail = s;
  337.                         head->next = NULL;
  338.                 }
  339.                 else
  340.                 {
  341.                         tail->next = s;
  342.                         tail = s;
  343.                         tail->next =NULL;
  344.                 }
  345.                 s = (lclientlink)malloc(sizeof(clientlink));
  346.         }
  347.         free(s);
  348.         close(fid);
  349.         return head;
  350. }
  351. /************************************************************************************************************************************************/
  352. int add_client(lclientlink head,unsigned char *buf)                    //創建連表
  353. {
  354.         int saveback = 0;
  355.         lclientlink p = head ,s = NULL,tail = NULL,p1 = head;
  356.         unsigned char name[6] = {0};
  357.         s = (lclientlink)malloc(sizeof(clientlink));
  358.         memcpy(name,buf,6);
  359.         while(p1 != NULL)                                                                //判斷此用戶明是否被注冊過
  360.         {
  361.                 if((strcmp((p1->username),name)) == 0 )
  362.                 {
  363.                         printf("hello\n");
  364.                         return -1;
  365.                 }
  366.                 p1 = p1->next;
  367.         }
  368.         memcpy((s->username),name,6);                                        //讀取buf中的  6 個字節數據
  369.         memcpy((s->userpsword),buf + 6,4);                                //讀取buf中的  4個字節數據
  370.         if(head == NULL)
  371.         {
  372.                 head = s;
  373.                 tail = s;
  374.                 p = s;
  375.                 head->next = NULL;
  376.         }
  377.         else
  378.         {
  379.                 while(p != NULL)
  380.                 {
  381.                         tail=p;
  382.                         p = p->next;
  383.                 }
  384.                 tail->next=s;
  385.                 tail = s;
  386.                 s->next=NULL;
  387.         }
  388.         saveback = save_link(head);
  389.         return saveback;
  390. }
  391. /************************************************************************************************************************************************/
  392. int save_link(lclientlink head)                                                                //存儲連表
  393. {
  394.         lclientlink p = head;
  395.         int fid ;
  396.         int writeback;
  397.         fid = open("client.ini",O_WRONLY|O_APPEND);
  398.         if(fid == -1)
  399.         {
  400.                 printf("open error \n");
  401.                 return -1;                                                                                //打開文件失敗返回-1
  402.         }
  403.         while(p != NULL)
  404.         {
  405.                 writeback = write(fid,p,sizeof(clientlink));
  406.                 if(writeback == -1)
  407.                 {
  408.                         printf("write error\n");
  409.                         return -1;                                                                        //寫入文件失敗返回-1
  410.                 }
  411.                 p = p->next;
  412.         }
  413.         close(fid);
  414.         return 1;                                                                                        //寫入成功返回1
  415. }
  416. /************************************************************************************************************************************************/
  417. void cmpname_psword(int fd,unsigned char *buf,unsigned char datalen)
  418. {                                                                                                        //服務器端處理客戶的登錄
  419.         lclientlink head = NULL,p = NULL;
  420.         int writeback = 0;
  421.         int cmpnameresult = 3;
  422.         int cmppswordresult = 3;
  423.         unsigned char name[6] = {0};
  424.         unsigned char psword[4] = {0};
  425.         onuser s = NULL;
  426.         memset(name,0,6);                                                                        //name數組清零
  427.         memset(psword,0,4);                                                                //psword數組清零
  428.         memcpy(name,buf,6);                                                                //將buf中的copy到name數組中去
  429.         memcpy(psword,buf + 6,4);                                                        //將剩下buf中的數據copy到psword數組中去
  430.         head = read_clientlink();
  431.         p = head;
  432.         while(p != NULL)
  433.         {
  434.                 cmpnameresult = strcmp((p->username),name);                      //對比名字
  435.                 cmppswordresult = strcmp((p->userpsword),psword);           //對比密碼
  436.                 if(cmpnameresult == 0&&cmppswordresult == 0)
  437.                 {
  438.                         s = reseach(onhead,fd);                                                    //連表中查找登錄客戶的ip 與  port
  439.                         memset(buf,0,sizeof(buf));
  440.                         buf[0]=1000%256;
  441.                         buf[1]=1000/256;
  442.                         buf[2]= 19;
  443.                         buf[3]= 1;                                                                               //成功返回1
  444.                         memcpy(&buf[4],(s->onip),16);
  445.                         printf("ip is %s\n",(s->onip));
  446.                         buf[20] = (s->onport)%256;
  447.                         buf[21] = (s->onport)/256;
  448.                         writeback = write(fd,buf,22);  //發送  4  個字節后     將在線連表 發送國去
  449.                         if(writeback == -1)
  450.                         {
  451.                                 printf("write error\n");
  452.                         }
  453.                         onhead = add_mes_to_onuser(name,fd,onhead);           //將登錄上的客戶信息補充完整
  454.                         record_onuser_send(fd,buf,onhead);//記錄登錄成功的客戶  并將登錄成功的好友信息發給剛上線的人
  455.                         break;
  456.                 }
  457.                 p = p->next;
  458.         }
  459.         memset(buf,0,sizeof(buf));
  460.         buf[0]=1000%256;
  461.         buf[1]=1000/256;
  462.         buf[2]= 1;
  463.         buf[3]= 2;                                                                                                //失敗返回2
  464.         writeback = write(fd,buf,strlen(buf));
  465.         if(writeback == -1)
  466.         {       
  467.                 printf("write error\n");
  468.         }
  469. }
  470. /************************************************************************************************************************************************/
  471. void add_onuser()                                                                                        //將剛連接上的客戶加到連表上的程序
  472. {
  473.                 onuser p = onhead ,s = NULL,tail =NULL;
  474.                 unsigned char onbuf[6] = {0};                                                       
  475.                 s = (onuser)malloc(sizeof(onclient));                                                //malloc一個新的空間
  476.                 s->onport = CLIENTPORT;                                                                //提取port
  477.                 s->onfd = CLIENT_FD;                                                                        //提取fd
  478.                 s->count = 0;                                       
  479.                 s->flag = 0;
  480.                 memcpy((s->onip),BUFIP,sizeof(BUFIP));                                                //提取ip
  481.                 memcpy((s->onuser),onbuf,sizeof(onbuf));                       
  482.                 if(onhead == NULL)
  483.                 {
  484.                         onhead = s;
  485.                         tail = s;       
  486.                         tail->onnext = NULL;
  487.                 }
  488.                 else
  489.                 {
  490.                         while(p != NULL)
  491.                         {
  492.                                 tail = p;
  493.                                 p = p->onnext;
  494.                         }       
  495.                         tail->onnext = s;
  496.                         tail = s;
  497.                         tail->onnext = NULL;
  498.                 }
  499. }
  500. /************************************************************************************************************************************************/
  501. onuser reseach(onuser onhead,int fd)                                //尋找剛上線客戶
  502. {
  503.         onuser p = onhead;
  504.         while(p != NULL)
  505.         {
  506.                 if((p->onfd) == fd)
  507.                 {
  508.                         return p;                                                        //返回剛上線的客戶地址
  509.                 }
  510.                 p = p->onnext;
  511.         }
  512. }
  513. /************************************************************************************************************************************************/
  514. onuser add_mes_to_onuser(unsigned char *name,int fd,onuser onhead)
  515. {
  516.         onuser p = onhead;
  517.         while(p != NULL)
  518.         {
  519.                 if((p->onfd) == fd)                //比較fd來添加姓名  和   將登錄成功的標志賦值
  520.                 {
  521.                         memcpy((p->onuser),name,6);        //補充名字
  522.                         p->flag = 1;                                        //賦值登錄成功的標志位
  523.                 }
  524.                 p = p->onnext;                                                //下一個節點
  525.         }
  526.         return onhead;                                                        //返回首指針
  527. }
  528. /************************************************************************************************************************************************/
  529. void record_onuser_send(int fd,unsigned char *buf,onuser onhead)
  530. {
  531.         onuser p = NULL,tail = NULL;
  532.         int writeback = 0;
  533.         p = onhead;
  534.         int i = 0;
  535.         uint16_t port = 0;
  536.         unsigned char datalen = 0;
  537.         unsigned char pack_len = 0;
  538.         printfonuser(onhead);
  539.         while(p !=NULL)                                //將連表中的所有在線的客戶發送給  剛上線的客戶
  540.         {
  541.                 if((p->flag) == 1)                                                                 //登錄成功的人才被發送出去
  542.                 {                       
  543.                         memcpy(&buf[4 + (16 + 2 + 6)*i + 0],(p->onip),16);    //將onip打包
  544.                         buf[4 + (16 + 2 + 6)*i + 16] = (p->onport)%256;         //將port打包
  545.                         buf[4 + (16 + 2 + 6)*i + 17] = (p->onport)/256;
  546.                         memcpy(&buf[4 + (16 + 2 +6)*i + 18],(p->onuser),6);//將名字打包
  547.                         i++;
  548.                 }
  549.                 p = p->onnext;                                                                           //指向下一個節點
  550.         }
  551.         datalen = 1 + (16 + 2 + 6)*i;
  552.         buf[0] = 1003%256;
  553.         buf[1] = 1003/256;
  554.         buf[2] = datalen;
  555.         buf[3] = i;
  556.         pack_len = 3 + datalen;
  557.         p = onhead;
  558.         while(p != NULL)
  559.         {
  560.                 if((p->flag) == 1)                                                        //尋找連表中登錄成功的人
  561.                 {
  562.                         writeback = write((p->onfd),buf,pack_len);
  563.                         if(writeback == -1)
  564.                         {
  565.                                 printf("write error\n");
  566.                         }
  567.                 }       
  568.                 p = p->onnext;       
  569.         }
  570. }
  571. /************************************************************************************************************************************************/
  572. void printfonuser(onuser onhead)                                        //打印在線客戶的程序
  573. {
  574.                 onuser p = onhead;
  575.                 if(p == NULL)
  576.                 {
  577.                         printf(" empty onuser  link\n");
  578.                 }
  579.                 while(p != NULL)
  580.                 {
  581.                         printf("name is %s\n",p->onuser);       
  582.                         printf("ip  is  %s\n",p->onip);       
  583.                         printf("port  is %d\n",p->onport);
  584.                         printf("fd is %d\n",p->onfd);
  585.                         printf("count is %d\n",p->count);
  586.                         printf("flag is %d\n",p->flag);
  587.                         p = p->onnext;
  588.                 }
  589. }
  590. /************************************************************************************************************************************************/
復制代碼





分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:106823 發表于 2016-4-19 09:03 | 只看該作者
好紐幣啊?床欢
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 老外几下就让我高潮了 | 我想看一级黄色毛片 | 国产一区 日韩 | 欧美视频1| 欧美国产精品一区二区三区 | 91精品国产综合久久久久久丝袜 | 人人玩人人添人人澡欧美 | 青春草国产 | 国产精品五月天 | 成人av在线播放 | 国产精品久久久久久久久免费相片 | 国产精品久久久久久久7777 | 一级毛片视频免费观看 | 日韩国产在线 | h视频网站在线观看 | 水蜜桃久久夜色精品一区 | 欧美精品一区免费 | 日韩成人在线一区 | 成人av一区二区三区 | 国产精品第2页 | 国产精品日韩一区二区 | 久久国产精品一区 | 久久精品国产一区二区三区 | 精品久久久久久久久久久久 | 亚洲精品一区二区在线观看 | 一级a性色生活片久久毛片 一级特黄a大片 | 国产一区二区免费 | 中文字幕亚洲一区二区三区 | 国产剧情一区 | 国产女人与拘做视频免费 | 国产欧美在线 | 日韩乱码在线 | 亚洲午夜视频 | 亚洲国产精品va在线看黑人 | 欧美a级网站 | 亚洲高清一区二区三区 | 人人做人人澡人人爽欧美 | 中文字幕日韩一区二区 | 狠狠操电影 | 成人免费视频网站在线看 | 999免费视频|