10、网络基础和SOCKET

10、网络基础和SOCKET

1、TCP/IP协议概述

  • TCP/IP是互联网的基础
  • OSI参考模型与TCP/IP参考模型对应关系:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yqkeHjJS-1590153327819)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200520210534189.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMMAF4pJ-1590153327849)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200520210637207.png)]

  • TCP/IP 实际上是一个一起工作的通信家族,为网际数据通信提供通路。为讨论方便可将
  • TCP/IP 协议组大体上分为三部分:
    • 1.Internet 协议(IP)
    • 2.传输控制协议(TCP)和用户数据报文协议(UDP)
    • 3.处于TCP 和UDP 之上的一组协议专门开发的应用程序。它们包括:TELNET,文件传送协议(FTP),域名服务(DNS)和简单的邮件传送程序(SMTP)等许多协议。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgzRURzv-1590153327852)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200520210804029.png)]

2、传输层协议 - TCP(传输控制协议)

  • 传输层协议。包括传输控制协议TCP和用户数据报文协议UDP。
  • 传输控制协议(TCP)。由于IP 提供非连接型传递服务,因此TCP应为应用程序存取网络创造了条件,使用可靠的面向连接的传输层服务。该协议为建立网际上用户进程之间的对话负责。此外,还确保两个以上进程之间的可靠通信。它所提供的功能如下:
    • 1.监听输入对话建立请求。
    • 2.请求另一网络站点对话。
    • 3.可靠的发送和接收数据。
    • 4.适度的关闭对话。

三次握手

  • 1、初始化主机通过一个同步标志置位的数据段发出会话请求。
  • 2、接收主机通过发回具有以下项目的数据段表示回复:同步标志置位、即将发送的数据段的起始字节的顺序号、应答并带有将收到的下一个数据段的字节顺序号。
  • 3、请求主机再回送一个数据段,并带有确认顺序号和确认号。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cQGPjwkJ-1590153327858)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200520211335682.png)]

3、传输层协议 - UDP(用户数据报文协议)

  • 用户数据报文协议(UDP)。UDP 提供不可靠的非连接型传输层服务,它允许在源和目的地站点之间传送数据,而不必在传送数据之前建立对话。此外,该协议还不使用TCP使用的端对端差错校验。当使用UDP时,传输层功能全都发挥,而开销却比较低。它主要用于那些不要求TCP协议的非连接型的应用程序。例如,名字服务、网络管理、视频点播和网络会议等。

4、应用层协议

  • Telnet
  • 文件传送协议(FTP 和TFTP)
  • 简单的邮件传送协议(SMTP)
  • 域名服务(DNS)等协议。

5、网络编程基础

socket概述

  • 为了简化开发通信程序的工作,由Berkely学校开发了一套网络通信程序的API函数标准
  • socket标准被扩展成window socket和unix socket
  • linux中的网络编程通过socket接口实现。Socket既是一种特殊的IO,它也是一种文件描述符。一个完整的Socket 都有一个相关描述{协议,本地地址,本地端口,远程地址,远程端口};每一个Socket 有一个本地的唯一Socket 号,由操作系统分配。

SOCKET分类

  • 流式套接字(SOCK_STREAM)
    • 流式的套接字可以提供可靠的、面向连接的通讯流。它使用了TCP协议。TCP 保证了数据传输的正确性和顺序性。
  • 数据报套接字(SOCK_DGRAM)
    • 数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。使用数据报协议UDP协议。
  • 原始套接字
    • 原始套接字允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。

套接字地址结构

struct sockaddr{
	unsigned short sa_family; /* address族, AF_xxx */
	char sa_data[14]; 	  /* 14 bytes的协议地址 */
};
//sa_family 一般来说, IPV4使用“AF_INET”。
//sa_data 包含了一些远程电脑的地址、端口和套接字的数目,它里面的数据是杂溶在一起的。

sockaddr_in地址结构

struct sockaddr_in {
	short int sin_family; /* Internet地址族 */
	unsigned short int sin_port; /* 端口号 */
	struct in_addr sin_addr; /* Internet地址 */
	unsigned char sin_zero[8]; /* 添0(和struct sockaddr一样大小)*/
};

字节序列转换

  • 因为每一个机器内部对变量的字节存储顺序不同(有的系统是高位在前,底位在后,而有的系统是底位在前,高位在后 ),而网络传输的数据大家是一定要统一顺序的。所以对与内部字节表示顺序和网络字节顺序不同的机器,就一定要对数据进行转换。

字节转换函数

  • htons()——“Host to Network Short”

    主机字节顺序转换为网络字节顺序(对无符号短型进行操作2bytes)

  • htonl()——“Host to Network Long”

    主机字节顺序转换为网络字节顺序(对无符号长型进行操作4bytes)

  • ntohs()——“Network to Host Short”

    网络字节顺序转换为主机字节顺序(对无符号短型进行操作2bytes)

  • ntohl()——“Network to Host Long ”

    网络字节顺序转换为主机字节顺序(对无符号长型进行操作4bytes)

地址格式转换

  • linux提供将点分格式的地址转于长整型数之间的转换函数。
    • inet_addr()能够把一个用数字和点表示IP 地址的字符串转换成一个无符号长整型。
    • inet_ntoa()
    • inet_aton()

基本套接字调用

socket()		bind()		    connect()	 
listen()		accept()		send()	
recv()		    sendto() 		shutdown()
recvfrom()		close()		 	getsockopt()      
setsockopt()		            getpeername()
getsockname()					gethostbyname()
gethostbyaddr()					getprotobyname()
fcntl()

基于流套接字的编程流程

6、socket示例

//server.cpp

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>

#define PORT 0x8888
int main(int argc,char *argv[])
{
    int sfp,nfp;
    static int number=0;
    struct sockaddr_in s_add,c_add;
    char buffer[1024]={0};
    printf("Hello,welcome to my server!\n");
    sfp=socket(AF_INET,SOCK_STREAM,0);
    if(-1==sfp){
        printf("socket fail!\n");
        return -1;
    }
    printf("socket ok!\n");

    bzero(&s_add,sizeof(struct sockaddr_in));
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=htonl(INADDR_ANY);
    s_add.sin_port=htons(PORT);
    if(-1==bind(sfp,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
        printf("bind fail!\n");
        return -1;
    }
    printf("bind ok!\n");

    if(-1==listen(sfp,5)){
        printf("listen fail!\n");
        return -1;
    }
    printf("listen ok\n");
    socklen_t addrlen = sizeof(struct sockaddr_in);

    while(1){
        nfp=accept(sfp,(struct sockaddr *)(&c_add),&addrlen);
        if(-1==nfp){
            printf("accept fail!\n");
            return -1;
        }
        printf("accept ok!\nServer start get connect from %#x :%#x\n",ntohl(c_add.sin_addr.s_addr),ntohs(c_add.sin_port));
        number++;
        int ret=fork();    
        if(ret>0){
            break;
        }
    }
    while(1){
        memset(buffer,0,sizeof(buffer));
        int len=read(nfp,buffer,sizeof(buffer));
        if(len>0){
            printf("client_%d:%s\n",number,buffer);
            write(nfp,buffer,sizeof(buffer));
        }
    }
    close(sfp);
    return 0;
}
//client.cpp

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 0x8888
int main(int argc,char *argv[])
{
    int cfd;
    int recbytes;
    char buffer[1024]={0};
    struct sockaddr_in s_add;
    printf("Hello,welcome to client !\n");

    cfd=socket(AF_INET,SOCK_STREAM,0);
    if(-1==cfd){
        printf("socket fail!\n");
        return -1;
    }
    printf("socket ok!\n");

    bzero(&s_add,sizeof(struct sockaddr_in));
    s_add.sin_family=AF_INET;
    s_add.sin_addr.s_addr=inet_addr("127.0.0.1");
    s_add.sin_port=htons(PORT);
    printf("s_addr=%#x,port : %#x\n",s_add.sin_addr.s_addr,s_add.sin_port);
    if(-1==connect(cfd,(struct sockaddr *)(&s_add),sizeof(struct sockaddr))){
        printf("connect fail!\n");
        return -1;
    }
    printf("connect to server success!\n");

    while(1){
        memset(buffer,0,sizeof(buffer));
        printf("please input:");
        fgets(buffer,sizeof(buffer),stdin);
        printf("\n");
        write(cfd,buffer,sizeof(buffer));
        memset(buffer,0,sizeof(buffer));
        if(-1==(recbytes=read(cfd,buffer,1024))){
            printf("read data fail!\n");
            return -1;
        }
        if(recbytes>0){
            printf("server:%s\n",buffer);
            //buffer[recbytes]='\0';
            //printf("%s\n",buffer);
        }
    }
    getchar();
    close(cfd);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值