• c语言学习5==TCP和socket


    socket实现不同服务器上的进程间的通信。

    socket是一个伪文件,分成两个部分:读缓冲区和写缓冲区。所以socket一旦建立就会在PCB中对应生成一个文件描述符fd。

     

     socket必须成对出现。

    =============================

    网络字节序:

    大小端:小端,低位存低地址,高位存高地址。大端相反。

    总之在网络间传递的包都是大端。

     网络字节序和主机字节序的转换

    点分十进制转网络大端

    1. #include
    2. #include
    3. int main(int argc,char *argv[])
    4. {
    5. //准备转换成大端的IP地址
    6. char buf[]="192.168.136.101";
    7. unsigned int num=0;
    8. //转成大端
    9. inet_pton(AF_INET,buf,&num);
    10. unsigned char * p=(unsigned char *)#
    11. printf("%d %d %d %d\n",*p,*(p+1),*(p+2),*(p+3));
    12. //大端转小端
    13. char ip[16]="";
    14. printf("%s\n",inet_ntop(AF_INET,&num,ip,16));
    15. return 0;
    16. }

    IPV4套接字结构体

     我们需要指定的就是协议 IP 端口,将这三个东西封装成一个结构体

    man 7 ip

    IPV4套接字结构体       

       struct sockaddr_in {
                   sa_family_t    sin_family; /* address family: AF_INET 协议 */
                   in_port_t      sin_port;   /* port in network byte order 端口*/
                   struct in_addr sin_addr;   /* internet address IP地址*/
               };

               /* Internet address. */
               struct in_addr {
                   uint32_t       s_addr;     /* address in network byte order */
               };
     

    通用套接字结构体

    TCP特点:出错重传,每次发送数据对方都会回ACK,可靠。

    socket服务器编写

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. int main(int argc, char *argv[])
    8. {
    9. //创建套接字/文件描述符
    10. int lfd = socket(AF_INET,SOCK_STREAM,0);
    11. //绑定。将协议和端口转成大端封装进结构体
    12. struct sockaddr_in addr;
    13. addr.sin_family = AF_INET;
    14. addr.sin_port = htons(8000);
    15. // addr.sin_addr.s_addr = INADDR_ANY;//绑定的是通配地址
    16. //此处将文件描述符绑定到本服务器的IP地址
    17. inet_pton(AF_INET,"192.168.136.101",&addr.sin_addr.s_addr);
    18. int ret = bind(lfd,(struct sockaddr *)&addr,sizeof(addr));
    19. if(ret < 0)
    20. {
    21. perror("");
    22. exit(0);
    23. }
    24. //监听
    25. listen(lfd,128);
    26. //提取
    27. struct sockaddr_in cliaddr;
    28. socklen_t len = sizeof(cliaddr);
    29. int cfd = accept(lfd,(struct sockaddr *)&cliaddr,&len);
    30. char ip[16]="";
    31. printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,
    32. ip,16), ntohs(cliaddr.sin_port));
    33. //读写
    34. char buf[1024]="";
    35. while(1)
    36. {
    37. bzero(buf,sizeof(buf));
    38. // int n = read(STDIN_FILENO,buf,sizeof(buf));
    39. // write(cfd,buf,n);
    40. int n =0;
    41. n = read(cfd,buf,sizeof(buf));
    42. if(n ==0 )//如果read返回等于0,代表对方关闭
    43. {
    44. printf("client close\n");
    45. break;
    46. }
    47. printf("%s\n",buf);
    48. }
    49. //关闭
    50. close(lfd);
    51. close(cfd);
    52. return 0;
    53. }

    三次握手

    多进程实现并发服务器

    与线程版进行对比

     gcc 02_process_tcp_server.c wrap.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include "wrap.h"
    7. void free_process(int sig)
    8. {
    9. pid_t pid;
    10. while(1)
    11. {
    12. pid = waitpid(-1,NULL,WNOHANG);
    13. if(pid <=0 )//小于0 子进程全部退出了 =0没有进程没有退出
    14. {
    15. break;
    16. }
    17. else
    18. {
    19. printf("child pid =%d\n",pid);
    20. }
    21. }
    22. }
    23. int main(int argc, char *argv[])
    24. {
    25. sigset_t set;
    26. sigemptyset(&set);
    27. sigaddset(&set,SIGCHLD);
    28. sigprocmask(SIG_BLOCK,&set,NULL);
    29. //创建套接字,绑定
    30. int lfd = tcp4bind(8008,NULL);
    31. //监
    32. Listen(lfd,128);
    33. //提取
    34. //回射
    35. struct sockaddr_in cliaddr;
    36. socklen_t len = sizeof(cliaddr);
    37. while(1)
    38. {
    39. char ip[16]="";
    40. //提取连接,
    41. int cfd = Accept(lfd,(struct sockaddr *)&cliaddr,&len);
    42. printf("new client ip=%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
    43. ntohs(cliaddr.sin_port));
    44. //fork创建子进程
    45. pid_t pid;
    46. pid = fork();
    47. if(pid < 0)
    48. {
    49. perror("");
    50. exit(0);
    51. }
    52. else if(pid == 0)//子进程
    53. {
    54. //关闭lfd
    55. close(lfd);
    56. while(1)
    57. {
    58. char buf[1024]="";
    59. int n = read(cfd,buf,sizeof(buf));
    60. if(n < 0)
    61. {
    62. perror("");
    63. close(cfd);
    64. exit(0);
    65. }
    66. else if(n == 0)//对方关闭j
    67. {
    68. printf("client close\n");
    69. close(cfd);
    70. exit(0);
    71. }
    72. else
    73. {
    74. printf("%s\n",buf);
    75. write(cfd,buf,n);
    76. // exit(0);
    77. }
    78. }
    79. }
    80. else//父进程
    81. {
    82. close(cfd);
    83. //回收
    84. //注册信号回调
    85. struct sigaction act;
    86. act.sa_flags =0;
    87. act.sa_handler = free_process;
    88. sigemptyset(&act.sa_mask);
    89. sigaction(SIGCHLD,&act,NULL);
    90. sigprocmask(SIG_UNBLOCK,&set,NULL);
    91. }
    92. }
    93. //关闭
    94. return 0;
    95. }

    1

    2

    3

    线程版服务器

    1. #include
    2. #include
    3. #include "wrap.h"
    4. typedef struct c_info
    5. {
    6. int cfd;
    7. struct sockaddr_in cliaddr;
    8. }CINFO;
    9. void* client_fun(void *arg);
    10. int main(int argc, char *argv[]){
    11. if(argc<2)
    12. {
    13. printf("argc<2 >>>> \n ./a.out 8000 \n");
    14. return 0;
    15. }
    16. short port=atoi(argv[1]);
    17. int lfd=tcp4bind(port,NULL);
    18. Listen(lfd,128);
    19. struct sockaddr_in cliaddr;
    20. socklen_t len=sizeof(cliaddr);
    21. CINFO *info;
    22. while(1){
    23. int cfd=Accept(lfd,(struct sockaddr *)&cliaddr,&len);
    24. char ip[16]="";
    25. printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&cliaddr.sin_addr.s_addr,ip,16),
    26. ntohs(cliaddr.sin_port)
    27. );
    28. pthread_t pthid;
    29. info=malloc(sizeof(CINFO));
    30. info->cfd=cfd;
    31. info->cliaddr=cliaddr;
    32. pthread_create(&pthid,NULL,client_fun,info);
    33. }
    34. return 0;
    35. }
    36. void* client_fun(void *arg)
    37. {
    38. CINFO *info=(CINFO *)arg;
    39. char ip[16]="";
    40. printf("new client ip =%s port=%d\n",inet_ntop(AF_INET,&(info->cliaddr.sin_addr.s_addr),ip,16),
    41. ntohs(info->cliaddr.sin_port));
    42. while(1)
    43. {
    44. char buf[1024]="";
    45. int count=0;
    46. count =read(info->cfd,buf,sizeof(buf));
    47. if(count<0)
    48. {
    49. printf("client close\n");
    50. break;
    51. }
    52. else if (count==0)
    53. {
    54. printf("clent close\n");
    55. break;
    56. }
    57. else
    58. {
    59. printf("%s\n",buf);
    60. write(info->cfd,buf,count);
    61. }
    62. }
    63. close(info->cfd);
    64. free(info);
    65. }

  • 相关阅读:
    kafka 消息偏移量
    比特币 ZK 赏金系列:第 2 部分——查找哈希冲突
    若依(Ruoyi-Vue-Plus版)——1.登录(SaToken)
    Unity调用API函数对系统桌面和窗口截图
    【面试:并发篇34:Unsafe】
    Matlab学习笔记
    本地 IDEA 卡死了!我把它跑在 Linux 服务器上!
    深入理解 Netty FastThreadLocal
    NOSQL Redis 数据持久化 RDB、AOF(二) 恢复
    Python机器学习:Sklearn快速入门(稍微懂一些机器学习内容即可)
  • 原文地址:https://blog.csdn.net/hebian1994/article/details/126633841