标准网络通信---TCP服务器的搭建

网络编程

      • 1、相关关键字和历史
        • (1)套接字
        • (2)相关历史:
        • (3)网络程序设计框架:C/S、B/S
        • (4)网络协议分层模型:
      • 2、网络接口编程
        • 1、套接字分类
          • (1)流式套接字
          • (2)数据报套接字
          • (3)原始套接字
      • 3、相关接口函数
        • socket()---创建套接字
        • bind()---绑定套接字
        • listen()---监听
        • accept()---接收客户端连接请求
        • connect()---(客户端)主动发送连接请求
        • read()/write()---数据收发
        • close()---关闭套接字
      • 4、TCP服务器搭建流程

进程间的通信有:管道、信号、system V ipc对象通信号灯集
前面的通信都局限于本主机,而当跨主机通信时就操作不了。

其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。

1、相关关键字和历史

(1)套接字

所谓【套接字】(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议根进行交互的接口
标准网络通信---TCP服务器的搭建_第1张图片

(2)相关历史:

​ 第一阶段:ARPAnet(阿帕网),是网络基础协议得雏形

​ 第二阶段:第一份IP协议说明书

​ 第三阶段:TCP/IP协议被制定

  • 协议:两者之间得一种约定

(3)网络程序设计框架:C/S、B/S

​ <1>C/S:表示客户端/服务器设计框架

  • ​ 优点:支持本地缓存(能实现较好的效果)、应用层协议可以自己灵活制定
  • ​ 缺点:开发工作量较大、用户安全性较低

​ <2>B/S:表示浏览器/服务器设计框架

  • ​ 优点:开发工作量较小、用户安全性较高
  • ​ 缺点:不支持本地缓存、应用层协议必须遵守http协议

(4)网络协议分层模型:

OSI分层模型:理想的网络分层模型

  • ​ 应用层
  • ​ 表示层
  • ​ 会话层
  • ​ 传输层
  • ​ 网络层
  • ​ 数据链路层
  • ​ 物理层

TCP/IP分层模型:一种标准的网络分层模型

  • ​ 应用层:http协议、tftp协议、NFS协议。。。
  • ​ 传输层:TCP协议、UDP协议。。。
  • ​ 网络层:IP协议、ICMP协议。。。
  • ​ 物理接口层:以太网协议、ARP协议、RAPP。。。
    eg:例如我们向另一台主机发送”还钱“
    标准网络通信---TCP服务器的搭建_第2张图片
    总结:

1.应用层:可以由用户自定义的协议,方便数据传输以及数据加密
2.传输层:提供端对端的数据传输
3.网络层:提供数据的路由
4.网络接口层:实现网络底层驱动

2、网络接口编程

Linux系统内核提供作为网络通信的接口

注:只有应用层是程序员能够自己定义的,下面三层的协议封装都是由内核完成的(但是又选择权力)

1、套接字分类

(1)流式套接字

数据以字节流(二进制流)的方式来进行传递,无大小限制,保证数据可靠,无丢失,顺序发送,主要用于TCP协议,一般情况下只要选择流式方式,那内核就会默认选择TCP传输层协议

(2)数据报套接字

主要通过数据报的方式发送,固定大小。不能保证数据可靠,可能丢失、乱序发送,主要用于UDP协议一般情况下只要选择数据报方式,那内核就会默认选择UDP传输层协议

(3)原始套接字

可以对较低层协议如IP、ICMP直接访问

3、相关接口函数

socket()—创建套接字

#include         
#include 

int  socket(int  domain, int type,int protocol);
参数:
    domain:domain参数指定通信域;这将选择用于通信的协议族。
      		这些系列被定义在中。
        目前被Linux内核理解的格式包括:
		AF_UNIX
        AF_LOCAL
        AF_INET 
        AF_AX25 
        AF_IPX 
        AF_APPLETALK 
        AF_X25 
        AF_INET6 
        AF_DECnet 
        AF_KEY ....
            
    type:套接字具有指定的类型,该类型指定通信语义。目前定义的类型有: 
      SOCK_STREAM  ---->流式套接字

      SOCK_DGRAM   ---->数据报套接字

      SOCK_RAW     ---->原始套接字
 
    protocol:协议指定套接字使用的特定协议。在给定的协议族中,通常只存在“一个协议”来支持特定的套接字类型,在这种情况下,“协议默认为0”。
          在多种协议这种情况下,特定的协议必须以这种方式指定。所使用的协议号特定于要在其中进行通信的“通信域”;参见getprotoent(3)了解如何将协议名称字符串映射到协议编号。
          

bind()—绑定套接字

#include           /* See NOTES */
#include 

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

listen()—监听

#include           /* See NOTES */
#include 

int listen(int sockfd, int backlog);
参数:
	sockfd:socket返回的监听套接字
    backlog:表示同时能够监听的客户个数(不是同时能连接的个数)
    返回值:0成功 -1结束

accept()—接收客户端连接请求

后续的数据通信全部使用通信套接字,不能使用监听套接字来通信

#include           /* See NOTES */
#include 

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
    sockfd:socket返回的监听套接字
    addr: 客户端首地址 如果不需要客户端信息传递-->NULL   
	addrlen:客户端地址信息长度 如果不需要客户端信息传递-->NULL
 返回值:
        成功返回用于通信的套接字,错误返回-1

connect()—(客户端)主动发送连接请求

#include           /* See NOTES */
#include 

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

read()/write()—数据收发

read------->
#include 

       ssize_t read(int fd, void *buf, size_t count);
	参数:
        fd:文件描述名
        buf:用户自定义的缓冲区,用于存放准备读入的内容
        count:请求读取的字节数
	返回值:成功返回读到的字节数,失败返回-1,返回0表示读到文件末尾
	----------------------------------------------------------------------------------------------------
	write------->
	#include 

       ssize_t  write(int fd, const void *buf,
       size_t count);
    参数:
            fd:文件描述名
            buf:用户自定义的缓冲区,用于存放准备写入的内容
            count:请求读取的字节数
        返回值:成功返回读到的字节数,失败返回-1

close()—关闭套接字

#include 

int close(int fd);//参数填套接字就行,很简单

4、TCP服务器搭建流程

(1)创建套接字----->socket() 正确返回:监听套接字 错误返回:-1

(2)套接字绑定------>bind() 绑定核心:IP地址PORT端口

(3)监听套接字

(4)建立链接请求

(5)读写

(6)关闭套接字

端口:标识进程 无符号短整型:0~65535 01024被内核使用。用户可指定端口:102465535
IP地址:标识主机 IPV4占四个字节。

形式点分十进制:“192.168.1.82”  给人看的
二进制形式:11000000 10101000 000000010 00000010 给计算机看的

IP地址转换函数

#include 
#include 
#include 

in_addr_t inet_addr(const char *)
cp:ip地址的字符串形式
in_addr_t:转换后的二进制地址形式    
   
 相关结构体(man 7 ip查询)
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 */
};    

5、实例:简单地搭建一个TCP服务器

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


int main(int argc, char *argv[])
{ 
    int sockfd=socket(AF_INET,SOCK_STREAM,0);//创建套接字,第一个参数为:协议族,第二个参数:套接字类型,第三个参数:0代表只存在一个协议来支持套接字类型
    if(sockfd==-1)//错误返回
    {
        perror("socket");
        exit(-1); 
    }
    struct sockaddr_in ser;//定义ip地址转化的相关结构体
    ser.sin_family=AF_INET;//初始化族
    ser.sin_port=htons(8989);//初始化端口---1024~65535都可以
    ser.sin_addr.s_addr=inet_addr("192.168.22.245");//初始化ip地址
    if(-1==bind(sockfd,(struct sockaddr *)&ser,sizeof(ser)))//绑定套接字
    {
        perror("bind");
        exit(-1);
    }
    printf("bind success\n");
    if(listen(sockfd,5)==-1)//监听套接字
    {
        perror("listen");
        exit(-1);
    }
    int connfd=accept(sockfd,NULL,NULL);//接受服务器/客户端连接请求
    while(1)
    {
        char buf[24]={0};//定义缓冲区大小
        if(connfd==-1)
        {
            perror("accept");
            exit(-1);
        }
        read(connfd,buf,24);//读取
        printf("%s\n",buf);//输出
        printf("accept success\n");
    }
    close(connfd);//关闭监听套接字
    close(sockfd);//关闭套接字

    return 0;
} 

代码运行结果展示:
标准网络通信---TCP服务器的搭建_第3张图片

你可能感兴趣的:(服务器,tcp/ip,网络,网络协议,ubuntu)