• Socket是针对端系统,也就是用户主机上开发程序,不涉及网络设备(交换机、路由器)
  • 独立于网卡驱动层之上,不涉及硬件,即基于Packet Driver编程

  • 端:是指通信双方两台电脑
  • 应用编程接口API 也就是两端 应用层内部的应用进程之间的  数据通信,遵循应用层协议,他们之间数据通信需要底层(传输层、网络层、数据链路层、物理层)的支持,底层一般是涉及到操作系统的知识
  • 应用进程 和 操作系统 之间需要一个接口,这个接口就是应用编程接口 API,这个接口API就是应用进程的控制权和操作系统的控制权之间进行转换的一个系统调用的接口。即应用进程通过API接口将控制权交给操作系统,操作系统执行完成之后将执行结果返还给我们的应用进程

  • 几种典型的应用编程接口

    • UNIX环境下  套接字接口  简称套接字 socket
    • 微软的 Windows Socket Interface 即 WINSOCK
  • Socket API
    • 适用于绝大多数操作系统
    • 实现了应用进程间通信的抽象机制
    • 面向多种协议栈接口 TCP /IP
    • Internet网络应用最为典型的API接口
    • 通信模型:客户/服务器 (C/S)架构

问题:主机和客户端都运行了多个应用进程,如何保证客户端进程和与之对应的服务器应用进程正确匹配呢?

  • IP地址只能区分 主机
  • 考虑到 跨主机进程通信需要传输层的支持,使用端口号区分 不同进程之间的标识

  • 服务器对外提供服务 需要提供 IP地址 + 端口号
  • 但是服务器内部使用套接字描述符来管理套接字,这个描述符本质就是一个结构体指针,结构体内部详细记录了字段对应的信息
  • Socket抽象,其操作类型对于文件的操作,将其看做一个特殊的文件
  • 返回的套接字描述符
    • 最为关键的是地址信息
    • 短点地址 = IP地址 + 端口号

  • 使用套接字的时候需要指定本地和远程的IP地址和端口号 ,就需要使用sockaddr_in设置端点地址,就包含了IP地址和端口号等信息

    • 地址族:一般使用AF_INET  涉及到不同的协议栈

Socket API函数 (WinSock)

  • 基于linux的socket进行扩充
  • 前面加入了WSA 表示这个版本的 套接字工具 采用动态链接库的方式进行创建

WSAStartup

WSACleanup

  • 不带WSA的函数接口适用于 WIN或者Linux,带上WSA的函数只能适用于win环境下
  • int WSACleanup(void);
  • 应用程序在完成对请求的Socket库的使用,最后需要调用WSACleanup函数,从而解除和Socket库的绑定,释放Socket库所占用的系统资源

socket

  • 创建套接字,衔接 应用层和传输层之间的数据通信

  • 套接字的类型

    • 使用的是TCP类型   套接字的类型是SOCK_STREAM
    • 使用的是UDP类型  套接字的类型是 SOCK_DGRAM
    • 跳过传输层,直接实现 应用层和网络层之间的数据通信,使用SOCK_RAW,需要特殊的权限,linux操作的话需要具备root权限,win需要用户具备管理员权限,其具备 上述两种方式的独特之处
  • TCP 和 UDP的区别
    • TCP:可靠 (数据不会出错、丢失、乱序等)、面向连接、字节流传输、点对点
    • UDP:不可靠、无连接、数据报传输

closesocket

  • win使用的是closesocket
  • linux使用的是close
  • int closesocket(SOCKET sd);
  • 关闭一个描述符为sd的套接字
  • 如果多个进程共享一个套接字的话,调用closesocket将套接字的引用计数减一,减少至0才会真正关闭
  • 一个进程中的多个线程对一个套接字的使用无计数
    • 即同一个进程中的一个线程使用closesocket关闭套接字,这个进程中的其余线程也不能访问这个套接字
  • 返回数值
    • 0  : 成功
    • SOCKET_ERROR  :  失败

bind

  • socket创建的时候,内部的套接字描述符并没有涵盖地址信息,比如IP地址和端口号,需要使用bind进行绑定,设定套接字的本地断点地址
  • 参数
    • 套接字描述符:也就是使用socket创建的
    • 端点地址
      • 结构 sockaddr_in
    • 客户程序不需要调用bind函数,因为操作系统会帮助用户填充IP地址和端口号
    • 服务器需要使用这个函数指定IP地址和端口号
      • IP地址如何绑定呢?

        • 如果主机安置了不同的网卡,分别连接在不同的网段,造成了网段隔离
        • 所以需要使用地址通配符  INADDR_ANY

listen

  • int listen(sd,queuesize);
  • 置服务器端的流套接字处于被动监听状态
    • 仅仅服务端调用
    • 仅用于面向连接的流套接字
  • 设置了连接请求队列的大小
  • 返回数值
    • 0 成功
    • SOCKET_ERROR:失败

connect

  • connect (sd,saddr,saddrlen)

    • 客户端套接字  sd
    • 特定计算机的特定端口  saddr
  • 只适用于客户端,使用connect函数和服务器进行连接
  • 通信协议
    • TCP:建立TCP连接

      • connect返回成功,表示建立连接,可以成功通信
    • UDP:指定服务器的端点地址
      • connect返回成功,可不一定会成功通信

accept

  • newsock = accept(sd,caddr,caddrlen);
  • 服务端调用accept函数从处于监听状态的流套接字sd中的客户连接请求队列中取出排在最前面的一个客户请求,并且创建一个新的套接字 衔接 来自客户端的套接字,形成一个通道
  • 注意事项:
    • 仅用于TCP套接字
    • 仅用于服务器
  • 创建新的套接字,使用新的套接字 和 客户端 进行通信
    • 原因

      • TCP是面向连接的、可靠的、点对点的。
      • 也就是客户端和服务端 通过一个Socket建立连接,然后创建新的socket负责 客户端和服务端的应用进程之间的通信,出于高并发的思想采用上述设计
      • 要不 服务端只能为一个客户端提供服务,就不能同时为其余客户端的用户进行服务
      • 主线程或主进程继续监听新的请求,子线程通过创建新的连接请求

send / send to

  • send (sd,*buf,len,flags)
  • sendto(sd,*buf,len,flags,destaddr,addrlen)
  • send函数TCP套接字(客户和服务器) 或调用了connnect函数的UDP客户端套接字,适用于TCP,因为已经连接了,就不需要ip地址和端口号了
  • sendto函数适用于UDP服务器套接字 与  没有调用connect函数的UDP客户端套接字

recv / recv from

  • recv(sd,*buffer,len,flags)
  • rtecvfrom(sd,*buf,len,flags,senderaddr,saddrlen)
  • recv 函数从TCP连接的另外一端接收数据,或者从调用了connect函数的UDP客户端套接字接收服务器发来的数据
  • recvfrom 函数从UDP服务器套接字与未调用connnect函数的UDP的客户端套接字接收对端数据

setsockopt 和 getsockopt  使用不多

小结

  • connect 如果是tcp的话是真正的连接,如果是UDP没有连接,仅仅指定一个端口和地址

网络字节顺序

  • 表示层 解决数据表示转换功能
  • TCP/IP 定义了标准的用于协议头中的二进制的整数表示:网络字节顺序
  • 某些Socket API函数的参数需要存储为网络字节顺序 (IP地址和端口号等等)
  • 可以实现本地字节顺序和网络字节顺序的转换
    • htons:   将本地字节顺序  转换为  网络字节顺序 (16bits)
    • ntohs:   将网络字节顺序  转换为 本地字节顺序 (16bits)
    • htonl :   将本地字节顺序  转换为  网络字节顺序 (32bits)
    • ntohl:    将网络字节顺序  转换为 本地字节顺序 (16bits)

解析服务器的IP地址

  • 客户端使用域名、IP地址标识服务器,但是IP协议需要的是32位二进制的IP地址,因此需要将域名或IP地址转换为32位IP地址
  • 函数
    • inet_addr() 实现点分十进制IP地址到32位IP地址的转换
    • gethostbyname()实现域名到32位IP地址的转换
      • 返回一个指向hostent结构体的指针

解析服务器(熟知)端口号

  • 客户端还可以使用 服务名 标识服务器端口
  • 需要将服务器名 转换为 熟知的端口号
  • 函数
    • getservbyname()

      • 返回一个指向servent结构的指针

解析协议号

  • 客户端可能使用协议名 如 TCP 指定协议
  • 需要将协议名转换为协议号 如 6
  • 函数
    • getprotobyname()实现协议名到协议号的转换
    • 返回一个指向结构protoent的指针

TCP客户端软件

  • 确定服务器的IP地址和端口号
  • 创建套接字
  • 分配本地端点地址(IP地址和端口号)
  • 连接服务器(套接字)
  • 遵循应用层协议进行通信
  • 关闭释放连接

UDP客户端软件

  • 确定服务器的IP地址和端口号
  • 创建套接字
  • 分配本地端点地址(IP地址和端口号)
  • 指定服务器端点地址 构造UDP数据包
  • 遵循应用层协议进行通信
  • 关闭释放连接

客户端软件的实现 connectsock()

  • 设计一个connectsock过程封装底层的代码
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<winsock.h>#ifdef INADDR_NONE
#define INADDR_NONE 0xffffffff
#endif /*INADDR_NONE*/void errexit(const char *);
/*connectsock --> allocate & connect a socket using TCP or UDP
*///host      服务器端点地址
//service   服务名
//transport 传输层协议
SOCKET connectsock(const char * host,const char* service,const char * transport){struct hostent     *phe;  //pointer to host information entry      struct servent     *pse;  //pointer to service information entrystruct protoent    *ppe;  //pointer to protocal iunformation entrystruct sockaddr_in sin;   //an Internet endpoint addressint s,type;               //socket descriptor and socket typememset(&sin,0,sizeof(sin));sin.sin_family = AF_INET;//Map service name to port numberif(pse = getservbyname(service,transport)){sin.sin_port = pse.s_port;}else if((sin.sin_port = htons((u_short)atoi(service))) == 0){errexit("can't get \"%s\" service entry\n",service);}//Map host name to IP address,allowing for dotted decimal_pointif(phe = gethostbyname(host)){memcpy(&cin.sin_addr,phe->h_addr,phe->h_length);}else if((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE){errexit("can't get \"%s\" host entry\n",host);}//Map protocol name to protocal numberif(ppe = getprotobyname(transport) == 0){errexit("can't get \"%s\" protocal entry\n",transport);}//Use protocal to choose a socket typeif(strcmp(transport,"udp")==0){type = SOCK_DGRAM;}else{type = SOCK_STREAM;}//Allocate a sockets = socket(PF_INET,type,ppe->p_proto);if(s == INVALID_SOCKET){errexit("can't create socket:%d",GetLastError());}//Connect the socketif(connect(s,(struct sockaddr*)&sin,sizeof(sin)) == SOCKET_ERROR){errexit("can't connect to %s.%s: %d\n",host,service,GetLastError());}return s;
}
  • UDP客户端 和 TCP客户端
#include <winsock.h>
SOCKET connectsock(const char*,const char*,const char*);//connectUDP -> connect to a specified UDP service on a specified host
SOCKET connectUDP(const char*host,const char* service){return connectsock(host,service,"udp")
}#include <winsock.h>
SOCKET connectsock(const char*,const char*,const char*);//connectUDP -> connect to a specified UDP service on a specified host
SOCKET connectTCP(const char*host,const char* service){return connectsock(host,service,"tcp")
}
  • 异常处理
#include<stdarg.h>
#include<stdio.h>
#include<stdlib.h>
#include<winsock.h>//errexit -> print an error message and exitvoid errexit(const char* format){va_list args;va_start(args,format);vfprintf(stderr,format,args);va_end(args);WSACleanup();exit(1);
}

访问DAYTIME服务的客户端

  • 获取日期和时间
  • 双协议服务(TCP\UDP)
  • 端口号为 13
  • localhost 说明 服务端和客户端都部署在同一台机器上
  • daytime 说明这是一个请求时间的服务

TCP

  • 代码采用循环接收信息的方式来接收,是因为tcp是一种流传输的协议,发送端发送的数据并不意味着接收端收到的数据一样 ,有可能数据切片

UDP

UDP使用数据报的方式,因此每次发送和接收的数据是完整的,因此不需要使用循环,只需要一次接收即可

四种类型基本服务器

  • 循环无连接  UDP

    • 流程

      • 创建套接字
      • 绑定端点地址 INADDR_ANY + 端口号
      • 反复接收来自客户端的请求
      • 遵循应用层协议,构造响应报文,发送给客户
    • 数据发送
      • 服务器不可以使用connect()函数
      • 无连接服务器使用sendto()函数发送数据报
    • 数据接收
      • 使用recvfrom函数接收数据,自动提取
  • 循环面向连接  TCP

    • 创建(主)套接字  并绑定端口号
    • 设置(主)套接字为被动监听模式,准备用于服务器
    • 调用accept()函数接收下一个请求(通过主套接字),创建新的套接字用于和客户端建立连接
    • 遵循应用层协议,反复接收客户请求,通过新的套接字构造并发送响应报文,发送给客户
    • 完成为特定的客户端服务之后,关闭和客户端之间的连接 返回步骤3
  • 并发无连接

    • 主线程 第一步 创建套接字  并绑定端口号
    • 主线程 第二步  反复调用recvfrom()函数 接收下一个客户端的请求,并创建新线程 处理客户响应
      • 子线程 第一步 接受特定的请求
      • 子线程 第二步 依据应用层的协议构造响应的报文  并调用sendto()发送
      • 子线程 第三步 退出(子线程处理完成一个请求之后便会终止)
    • 注意事项:
      • 主线程仍然在调用 recvfrom函数,不断的接收请求 创建线程响应服务
  • 并发面向连接
    • 主线程 第一步 创建(主)套接字  并绑定端口号
    • 主线程 第二步 设置(主)套接字为被动监听模式,准备用于服务器。
    • 主线程 第三部 反复调用accept()函数 创建主套接字,接收下一个客户端的下一个连接请求,并创建新线程 处理客户响应
      • 子线程 第一步 接受特定的请求
      • 子线程 第二步 依据应用层的协议与特定的用户进行交互
      • 子线程 第三步 退出(子线程处理完成一个请求之后便会终止)(线程终止)

代码

无连接循环 DAYTIME服务器

面向连接的并发的DAYTIME服务器

Socket编程 涵盖代码和函数参数介绍相关推荐

  1. 在QT中使用socket编程:解决connect函数名称冲突

    问题 当使用QT做可视化界面的时候,我们知道connect函数是连接函数,用于连接信号与槽,但connect在C/C++的socket网络编程中也是一个必不可少的函数,作用是发送连接请求,建立tcp连 ...

  2. socket学习01(socket函数参数介绍)

    socket套接字函数接口参数: 1.SOCKET sock = socket(int af, int type, int protocol); (1)af 为地址族(Address Family), ...

  3. 全球最大的社交编程及代码托管网站Github介绍

    前言 上篇文章介绍了git,这篇文章呢来介绍一下GitHub,废话不多说我们直接进入主题吧. 一.了解Github 1.1什么是版本控制系统 版本控制是一种记录一个或若干个文件内容变化,以便将来查阅特 ...

  4. python机器学习minimize函数参数介绍及作用

    一.问题介绍 在初学机器学习时,在吴恩达机器学习课后作业中经常使用到高级优化算法,计算theta值会更为便捷,在python中,可以使用scipy.optimize包中的minimize函数直接计算得 ...

  5. tcp java实例_实现了基于TCP的Java Socket编程实例代码

    实现了基于TCP的Java Socket编程,功能很简单:客户端向服务器端输出一名话"connect",服务器端接收输出到控制台并向客户端输出一名话"Hello" ...

  6. 网络编程 socket函数参数介绍

    SOCKET参数: 1.地址的类型 a.AF_INET 2  internet协议版本4(ipv4)地址系列. b.AF_INET6 23  Internet协议版本6(ipv6)地址系列. c.AF ...

  7. socket编程:从send函数和sendto函数参数的不同看TCP和UDP的差别。

    ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const v ...

  8. linux网络编程之Listen函数参数介绍

    1.listen()函数介绍 listen函数使用主动连接套接口变为被连接套接口,使得一个进程可以接受其它进程的请求,从而成为一个服务器进程.在TCP服务器编程中listen函数把进程变为一个服务器, ...

  9. socket编程之回声服务器函数的陷阱

    由connect函数使用不当导致的小错误 话不多说先看代码: server.c #include<stdio.h> #include<ctype.h> #include< ...

最新文章

  1. JSR-303校验类型
  2. QSetting介绍
  3. MySQL数据库备份工具mysqldump的使用(转)
  4. vue 在已有的购买列表中(数据库返回的数据)修改商品数量
  5. ubuntu16.04源码安装python3.7
  6. 计算机行政考试题库,2014香港特别行政区计算机等级考试试题 二级ACCESS考试题库...
  7. 利用计算机测地震是计算机的什么,计算机在气象预报、地震探测、导弹卫星轨迹等方面的应用都属于( )...
  8. Java记录 -45- List的toString方法
  9. 后缀转中缀表达式_中缀转后缀表达式代码实现(下)及计算器完整版
  10. ASP分页要用到的属性ADO CursorLocation知识补充:
  11. Linux下安装PHP扩展
  12. 华为ENSP远程登录
  13. Scrapy爬取二手房信息
  14. 网易im即时通讯 移动端嵌入web
  15. css 取偶数节点_css3 nth 选择器
  16. java ssm框架调用微信_Java开发SSM框架微信退款的实现
  17. 简单两步搞定小米路由新增功能-DDNS
  18. java环境搭建及概述
  19. Microsoft Excel 教程:如何在 Excel 中使用 XLOOKUP 函数?
  20. 时序电路——DFF再理解

热门文章

  1. java 匿名内部类 百科_java匿名内部类具体概念是什么,在什么地方用到?
  2. 解决IDL检索COM类工厂中CLSID为{ }组件注册失败
  3. 【转】__declspec用法详解
  4. ABP入门系列(17)——使用ABP集成的邮件系统发送邮件
  5. 让SharePoint站点输出详细错误信息[转]
  6. 老王说ros的tf库
  7. ros amcl 参数配置
  8. usb接口供电不足_AMD RX 6000 系列显卡配备USB-C 接口,支持外接供电
  9. linux 中将文件设置密码,linux – 如何使用公钥在openssl中加密大文件
  10. 【POJ - 2349】【UVA - 10369】 Arctic Network(最小生成树求权值第k大的边)(内附两种算法)