zoukankan      html  css  js  c++  java
  • 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例

    TCP客户与服务器进程之间发生的重大事件时间表

    TCP服务器

    socket() --- bind() --- listen() --- accept() --- read() --- write --- read() --- close

    TCP客户

    socket() --- connect() --- write() --- read()  --- close()


    套接字函数简介

    int socket(int family, int type, int protocol);

    指定要用的通信协议类型

    int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

    客户用connect()来建立与TCP服务器的连接

    int bind(int sockfd, const struct sockaddr *myaddr, scoklen_t addrlen);

    把一个本地协议地址赋予一个套接字

    int listen(int sockfd, int backlog);

    设置套接字为被动套接字,指示内核接收向该套接字的连接请求

    int accept(int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen);

    由TCP服务器调用, 用来从已完成连接队列队头返回下一个已完成连接

    pid_t fork(void);

    产生子进程

    int close(int sockfd);

    关闭套接字, 并终止TCP连接


    典型的并发服务器程序轮廓

    1. pid_t pid;
    2. int listenfd, connfd;
    3. listenfd=Socket(...);
    4. Bind(listenfd, ...);
    5. Listen(listenfd,LISTENQ);
    6. for(;;){
    7. connfd=Accept(listenfd, ...);
    8. if((pid=Fork())==0){//如果是子进程
    9. Close(listenfd);//子进程关闭其监听套接字
    10. doit(connfd);//处理需求
    11. Close(connfd);//关闭子进程的已连接套接字
    12. exit(0);//子进程终止
    13. }
    14. Close(connfd);//父进程关闭已连接套接字
    15. }


    TCP echo服务器程序

    1. #include "unp.h"
    2. #include <time.h>
    3. void srv_echo(int sockfd)
    4. {
    5. ssize_t n;
    6. char buf[1000];
    7. again:
    8. while((n=read(sockfd,buf,1000))>0)
    9. Writen(sockfd,buf,n);
    10. if(n<0 && errno==EINTR)
    11. goto again;
    12. else if(n<0)
    13. err_sys("srv_echo: read error");
    14. }
    15. int
    16. main(int argc,char ** argv)
    17. {
    18. int listenfd, connfd;
    19. pid_t childpid;
    20. socklen_t clilen;
    21. struct sockaddr_in cliaddr, servaddr;
    22. char buff[1000];
    23. listenfd=Socket(AF_INET, SOCK_STREAM, 0);
    24. bzero(&servaddr, sizeof(servaddr));
    25. servaddr.sin_family=AF_INET;
    26. servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
    27. servaddr.sin_port=htons(1234);
    28. Bind(listenfd, (SA*) &servaddr, sizeof(servaddr));
    29. Listen(listenfd, 100);
    30. for(;;){
    31. clilen=sizeof(cliaddr);
    32. connfd=Accept(listenfd, (SA*) &cliaddr, &clilen);
    33. printf("connection from %s , port %d ",
    34. inet_ntop(AF_INET,&cliaddr.sin_addr, buff, sizeof(buff)),
    35. ntohs(cliaddr.sin_port));
    36. if((childpid=Fork())==0){
    37. Close(listenfd);
    38. srv_echo(connfd);
    39. exit(0);
    40. }
    41. Close(connfd);
    42. }
    43. }



    TCP echo客户端程序

    1. #include "unp.h"
    2. void cli_echo(FILE *fp, int sockfd)
    3. {
    4. char sendline[1000], recvline[1000];
    5. while(Fgets(sendline,1000, fp)!=NULL){
    6. Writen(sockfd, sendline, strlen(sendline));
    7. if(Readline(sockfd, recvline, 1000)==0)
    8. err_quit("cli_echo: server terminated prematurely");
    9. Fputs(recvline, stdout);
    10. }
    11. }
    12. int
    13. main(int argc, char **argv)
    14. {
    15. int sockfd;
    16. struct sockaddr_in servaddr;
    17. if(argc!=2)
    18. err_quit("usage: tcpcli <IPaddress>");
    19. sockfd=Socket(AF_INET, SOCK_STREAM, 0);
    20. bzero(&servaddr, sizeof(servaddr));
    21. servaddr.sin_family=AF_INET;
    22. servaddr.sin_port=htons(1234);
    23. Inet_pton(AF_INET,argv[1], &servaddr.sin_addr);
    24. Connect(sockfd, (SA*) &servaddr, sizeof(servaddr));
    25. cli_echo(stdin,sockfd);
    26. exit(0);
    27. }




    这一章的API讲解非常有逻辑性, 讲解的过程可以看到这样设计的合理性

    4.5 listen函数

    当一个客户的SYN到达, 若服务器的相应监听套接字维护的队列已经满了,  TCP就会忽略该分节, 也就是不发送RST. (这里的TCP指的是实现TCP的内核)

    之所以这样设计有两点理由: 

    (1)这种情况是暂时的, TCP的正常重传机制会处理这个问题

    (2)客户无法区分这个RST意思是 "该端口没有服务器在监听" 还是 "该端口有服务器在监听, 不过队列已满"







  • 相关阅读:
    buuctf-web [强网杯 2019]随便注 1
    buuctf-crypto 引用可打印
    buuctf-crypto 变异凯撒
    buuctf-misc 文件中的秘密
    buuctf-misc LSB
    nginx 模块配置
    cloudflare CDN下nginx获取用户真实IP地址
    使用nginx后如何在web应用中获取用户ip及原理解释
    获取用户真实 ip 地址的 nginx 相关配置
    解决nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)
  • 原文地址:https://www.cnblogs.com/gremount/p/5768432.html
Copyright © 2011-2022 走看看