首页 > 系统相关 >Unix/Linux系统编程第十三章学习笔记

Unix/Linux系统编程第十三章学习笔记

时间:2022-11-12 14:45:19浏览次数:44  
标签:printf addr IP 编程 TCP server Unix Linux include

第十三章 TCP/IP和网络

13.2 TCP协议

  • TCP/IP(Comer1988,2001;RFC11801991)是互联网的基础。TCP代表传输控制协议。IP代表互联网协议。目前有两个版本的IP,即IPv4和IPv6。IPv4使用32位地址,IPV6则使用128位地址。
    本节围绕IPv4进行讨论,它仍然是目前使用最多的IP版本。TCP/IP的组织结构分为几个层级,通常称为TCP/IP堆栈。图13.1所示为TCP/IP的各个层级以及每一层级的代表性组件及其功能。

    顶层是使用TCPIP的应用程序。用于登录到远程主机的ssh、用于交换电子邮件的mail、用于Web页面的htp等应用程序需要可靠的数据传输。通常,这类应用程序在传输层使用TCP。另一方面,有些应用程序,例如用于查询其他主机的ping命令,则不需要可靠性。这类应用程序可以在传输层使用UDP来提高效率(RFC7681980;Comer1988)。传输层负责以包的形式向IP主机发送/接收来自IP主机的应用程序数据。进程与主机之间的传输层或其上方的数据传输只是逻辑传输。实际数据传输发生在互联网(IP)和链路层,这些层将数据包分成数据,以便在物理网络之间传输。图13.2所示为TCP/IP网络中的数据流路径。

13.3 IP主机和IP地址

  • 主机是支持TCP/IP协议的计算机设备。每个主机由一个32位的IP地址来标识。

  • IP地址分为两部分,即 NetworkID 字段和HostID字段。根据划分,IP 地址分为A~E 类。例如,一个B类IP地址被划分为一个16位NetworkID,其中前2位是10,然后是一个16位的 HostID字段。发往IP地址的数据包首先被发送到具有相同 networkID的路由器。路由器将通过 HostID 将数据包转发到网络中的特定主机。每个主机都有一个本地主机名localhost,默认 IP地址为 127.0.0.1。本地主机的链路层是一个回送虚拟设备,它将每个数据包路由回同一个localhost。这个特性可以让我们在同一台计算机上运行TCP/IP 应用程序,而不需要实际连接到互联网。

13.4 IP协议

  • IP协议用于在 IP主机之间发送/接收数据包。IP尽最大努力运行。IP 主机只向接收主机发送数据包,但它不能保证数据包会被发送到它们的目的地,也不能保证按顺序发送。这意味着IP 并非可靠的协议。必要时,必须在IP 层的上面实现可靠性。下图所示是IP头格式:

13.7/8 UDP/TCP

  • UDP(用户数据报协议在IP上运行,用于发送/接收数据报。与IP类似,UDP不能保证可靠性,但是快速高效。它可用于可靠性不重要的情况。

  • TCP(传输控制协议)是一种面向连接的协议,用于发送/接收数据流。TCP也可在IP 上运行,但它保证了可靠的数据传输。通常,UDP类似于发送邮件的USPS,而TCP类似于电话连接。

13.9 端口编号

  • 应用程序 =(主机 IP,协议,端口号)
    其中,协议是TCP或 UDP,端口号是分配给应用程序的唯一无符号短整数。要想使用UDP或 TCP,应用程序(进程)必须先选择或获取一个端口号。前1024个端口号已被预留。其他端口号可供一般使用。应用程序可以选择一个可用端口号,也可以让操作系统内核分配端口号。

13.13 套接字编程

  • 套接字地址
struct sockaddr_in {
sa_family_t sin_family; // AF_INET for TCP/IP
// port number
in_port_t sin_port;
struct in_addr sin_addr;// IP address );
// internet address struct in_addr {
// IP address in network byte order
s_addr;
uint32_t
);
  • 套接字API
  • 服务器必须创建一个套接字,并将其与包含服务器IP 地址和端口号的套接字地址绑定。它可以使用一个固定端口号,或者让操作系统内核选择一个端口号(如果 sin port为0)。
    为了与服务器通信,客户机必须创建一个套接字。对于UPD套接字,可以将套接字绑定到服务器地址。如果套接字没有绑定到任何特定的服务器,那么它必须在后续的 sendto()/recvfrom()调用中提供一个包含服务器IP 和端口号的套接字地址。

Socket编程实践

  • 代码:
    client端
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>  /* netdb is necessary for struct hostent */
#include <time.h>

#define PORT 4321   /* server port */

#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
    time_t t1,t2;
    int sockfd, num;    /* files descriptors */
    char buf[MAXDATASIZE],mes[MAXDATASIZE];    /* buf will store received text */
    struct hostent *he;    /* structure that will get information about remote host */
    struct sockaddr_in server;

    if (argc != 2)
    {
        printf("Usage: %s <IP Address>\n",argv[0]);
        exit(1);
    }

    if((he=gethostbyname(argv[1]))==NULL)
    {
        printf("gethostbyname() error\n");
        exit(1);
    }

    if((sockfd=socket(AF_INET,SOCK_STREAM, 0))==-1)
    {
        printf("socket() error\n");
        exit(1);
    }
    bzero(&server,sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *((struct in_addr *)he->h_addr);
    if(connect(sockfd, (struct sockaddr *)&server, sizeof(server))==-1)
    {
        printf("connect() error\n");
        exit(1);
    }
    char str[100];
    time(&t1);
    printf("your PW:");
    
    scanf("%s",str);
    time(&t2);
    if(t2-t1>5)
      {
	printf("overtime\n");
	close(sockfd);
	return 0;
	   }
   
   
	
    if((num=send(sockfd,str,sizeof(str),0))==-1){
        printf("send() error\n");
        exit(1);
    }
    if((num=recv(sockfd,buf,MAXDATASIZE,0))==-1)
    {
        printf("recv() error\n");
        exit(1);
    }
    buf[num-1]='\0';
    if(buf[0]=='0')
      {
    printf("error\n");
    
    close(sockfd);
    return 0;
      }
    while(1){
    printf("hello,what do you want sent?\n");
    
    scanf("%s",mes);
    send(sockfd,mes,sizeof(mes),0);
    recv(sockfd,mes,MAXDATASIZE,0);
    printf("%s",mes);
    }
    
    return 0;
}


server端:

#include <stdio.h>
#include <arpa/inet.h>//inet_addr() sockaddr_in
#include <string.h>//bzero()
#include <sys/socket.h>//socket
#include <unistd.h>
#include <stdlib.h>//exit()

#define BUFFER_SIZE 1024

int main() {

    char listen_addr_str[] = "0.0.0.0";
    size_t listen_addr = inet_addr(listen_addr_str);
    int port = 8080;
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_size;
    char buffer[BUFFER_SIZE];//缓冲区大小
    int str_length;
    server_socket = socket(PF_INET, SOCK_STREAM, 0);//创建套接字
    bzero(&server_addr, sizeof(server_addr));//初始化
    server_addr.sin_family = INADDR_ANY;
    server_addr.sin_port = htons(port);
    server_addr.sin_addr.s_addr = listen_addr;
    if (bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
        printf("绑定失败\n");

        exit(1);

    }

    if (listen(server_socket, 5) == -1) {

        printf("监听失败\n");

        exit(1);

    }

    printf("创建tcp服务器成功\n");

 

 

    fd_set reads,copy_reads;

    int fd_max,fd_num;

    struct timeval timeout;

 

    FD_ZERO(&reads);

    FD_SET(server_socket,&reads);

    fd_max=server_socket;

 

 

    while (1) {

        copy_reads = reads;

        timeout.tv_sec = 5;

        timeout.tv_usec = 5000;

 

       

        if((fd_num = select(fd_max+1, &copy_reads, 0, 0, &timeout)) == -1) {

            perror("select error");

            break;

        }

        if (fd_num==0){//没有变动的socket

            continue;

        }

 

        for(int i=0;i<fd_max+1;i++){

            if(FD_ISSET(i,&copy_reads)){

                if (i==server_socket){//server_socket变动,代表有新客户端连接

                    addr_size = sizeof(client_addr);

                    client_socket = accept(server_socket, (struct sockaddr *) &client_addr, &addr_size);

                    printf("%d 连接成功\n", client_socket);

                    char msg[] = "恭喜你连接成功";

                    write(client_socket, msg, sizeof(msg));

                    FD_SET(client_socket,&reads);

                    if(fd_max < client_socket){

                        fd_max=client_socket;

                    }

                }else{

                    memset(buffer, 0, sizeof(buffer));

                    str_length = read(i, buffer, BUFFER_SIZE);

                    if (str_length == 0)   

                    {

                        close(i);

                        printf("连接已经关闭: %d \n", i);

                        FD_CLR(i, &reads);//从reads中删除相关信息

                    } else {

                        printf("%d 客户端发送数据:%s \n", i, buffer);

                        write(i, buffer, str_length);//将数据发送回客户端

                    }

                }

            }

        }

 

    }

 

    return 0;

}
  • 实践结果:
    实现两端数据交互

标签:printf,addr,IP,编程,TCP,server,Unix,Linux,include
From: https://www.cnblogs.com/wdys12138/p/16883730.html

相关文章

  • 软件工程实验二 结对编程
    一、题目要求我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:(1)能够自动生成四则运算练习题(2)可以定制题目数量(3)用户可以选择运算符(4)用户设置......
  • 经典编程算法
    经典编程算法点击查看代码1、快速排序算法2、堆排序算法3、归并排序4、二分查找算法5、BFPRT(线性查找算法)6、DFS(深度优先搜索)7、BFS(广度优先搜索)8、Floyd-Warsha......
  • GUI编程
    学习文档:https://www.cnblogs.com/programthinking/p/13845265.html学习视频:https://www.bilibili.com/video/BV1DJ411B75F/ 2.1AWT介绍AWTAbstractWindowsTools......
  • linux多命令的顺序执行
    当我们需要一次执行多个命令的时候,命令之间需要用连接符连接,不同的连接符有不同的效果。(1);分号,没有任何逻辑关系的连接符。当多个命令用分号连接时,各命令之间的执行成......
  • 关于Redhat-Linux中-compat-sap-c++软件包的说明
    本文OS版本:RedHatEnterpriseLinuxrelease8.6(Ootpa)还是先说一下compat-sap-c++软件包的作用:InordertorunSAPapplicationscompiledwithcertainnewerGCC......
  • 电影推荐系统项目实战:环境配置与搭建-----Linux环境下GIT、 Azkaban的安装与环境配置
    1.安装Git  2.通过git下载Azkaban源代码  3.切换到3.36版本  4.安装编译环境sudoyuminstallgccsudoyuminstall-ygcc-c++*  ./gr......
  • 编写C程序,实现顺序栈的下列功能: 1、设计一个虚拟界面,让用户选择操作(根据提示输入数据
    编写C程序,实现顺序栈的下列功能: 1、设计一个虚拟界面,让用户选择操作(根据提示输入数据)2、采用模块化编程思想,编写main函数和若干子函数(实现功能)3、栈的基本功能有:创......
  • 不同编程语言的“Hello World”
    当我们学习一门编程语言时,都是从“Hello,World!”开始。所有程序员在其职业生涯中,都至少接触过一个经典的“Hello,World!”程序。通常程序员会使用多种编程语言,多的甚至......
  • Linux下的网络管理工具—OpenNMS
    OpenNMS的是一个运营商级别的,高度集成的,开放源码的平台,用于构建网络监控解决方案。OpenNMS有两个发行版:MeridianandHorizon。使用Meridian是可取的,对企业提供稳定和长期的......
  • linux服务器中JDK的安装和配置
    目录​​一、安装配置过程如下:​​​​1.新建jdk文件夹(/usr/local/jdk)​​​​2.将jdk.tar.gz包解压到jdk文件夹下​​​​ 3.jdk包解压后​​​​4.进入JDK环境变量添加......