Socket编程 涵盖代码和函数参数介绍

  • 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服务器

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446151.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springcloud阿里巴巴五大组件_如何无缝迁移 SpringCloud/Dubbo 应用到 Serverless 架构

简介&#xff1a; 本文分为三部分来介绍&#xff0c;分别介绍微服务应用迁移到 SAE 的优势&#xff0c;如何迁移 SpringCloud/Dubbo 应用到 SAE 上&#xff0c;以及针对 SpringCloud 应用迁移的实践演示。背景通过前面几节课程的学习&#xff0c;相信大家对于 SAE 平台已经有了…

frame中src怎么设置成一个变量_Go 语言设计哲学之七:变量声明须一致

Go 语言&#xff0c;使用变量之前需要先进行变量的声明。var s string “Golang"n : 666Go 语言有两类变量包级别(package varible)&#xff1a;在 package 级别可见的变量。如果是导出变量&#xff0c;该变量也可以被视为全局变量&#xff1b;局部变量(local varible)&a…

getdevicecaps在哪个头文件里_一招定胜负,while (true) 和 for (;;) 到底哪个更快

在JDK8u的jdk项目下做个很粗略的搜索&#xff1a;mymbp:/Users/me/workspace/jdk8u/jdk/src$ egrep -nr "for (s?;s?;" . | wc -l 369mymbp:/Users/me/workspace/jdk8u/jdk/src$ egrep -nr "while (true" . | wc -l 323并没有差多少。其次&#…

SM4 ECB加密模式 数据对比试验论证

程序如下 开启服务器密码机&#xff0c;调用SM4加密函数&#xff0c;需要注意的是程序输入的数据全部使用Hex 十六进制的格式 Key IV Data IV 00000000000000000000000000000000Source(加密数据) char input_date[] {a,a,a,a,.......} Ascll编码 需要转16进制input_data …

二分法查找c语言程序_C语言的那些经典程序 第十四期

戳“在看”一起来充电吧!C语言的那些经典程序 第十四期本期小C给大家带来三个用C语言解决实际问题的典例。如果全都理解&#xff0c;相信肯定能给大家带来收获&#xff01;接下来让我们看看是哪些程序吧&#xff01;1字符查找源程序&#xff1a;运行结果&#xff1a;程序分析:该…

centos网络隔一段时间就断_计算机网络总结

POST跟GET的区别作用GET用于获取资源&#xff0c;而POST用于传输实体参数GET的参数以字符串的格式出现在URL中&#xff0c;而POST的参数存储在请求实体中。因为URL只支持ASCII码&#xff0c;故GET的参数如果存在中文等字符就需要先进行编码&#xff0c;POST参考支持标准字符集。…

使用wireshark抓包,本地环回测试通信数据已经通过SM4国密算法加密

具体操作 本实验采用 本地环回测试开启wireshark抓包工具&#xff0c;设定端口号 tcp.port 5099 &#xff08;5099为服务端对外开启服务的端口号&#xff09;&#xff0c;不可以使用ip.addr指定ip地址&#xff0c;因为本地环回测试&#xff0c;相关信息太多&#xff0c;使用端…

public 函数_UE4精品教程 | 渲染编程(C++篇)【第三卷:从仿函数到std::function再到虚幻4Delegate】...

本文转载于YivanLee知乎作者专题目录链接&#xff1a;https://zhuanlan.zhihu.com/p/67694999这几天研究了一下虚幻4的delegate&#xff0c;但是想要理解这个&#xff0c;还得从仿函数说起。下面是一段代码例子&#xff1a;class MyFunctor{ public: int operator()(int …

C语言深度剖析书籍学习记录 第一章 关键字

C语言标准定义了32个关键字 union声明联合数据类型 Union declaration - cppreference.com维护足够的空间来置放多个数据成员中的“一种”&#xff0c;而不是为每一个数据成员配置空间&#xff0c;在 union 中所有的数据成员共用一个空间&#xff0c;同一时间只能储存其中一个…

js页面自适应屏幕大小_移动端自适应布局方法的calc()与vw

前端人员在处理移动端自适应布局时&#xff0c;目前前端最流行的方法应该就是使用媒体查询&#xff0c;来设置HTML的字体大小&#xff0c;然后用rem为单位对Dom的宽高进行设置&#xff0c;这个方法的优势在于兼容性方面很好&#xff0c;劣势则在于当前市场上不同的机型太多&…

C语言深度剖析书籍学习记录 第二章 符号

\ 连接符号&#xff0c;// \ 可以把下一行也注释调编译器 删除注释时&#xff0c;会使用空格进行替代

详细描述三个适于瀑布模型的项目_IT项目管理笔记——方法选择和软件评估

一、管理需求为什么要管理需求&#xff1f;避免失败&#xff0c;提高项目的成功率和需求管理所带来的其他好处软件生命周期中&#xff0c;一个错误发现得越晚&#xff0c;修复错误的费用越高许多错误是潜伏的&#xff0c;并且在错误产生后很长一段时间才被检查出来在需求阶段&a…

Socket通信 客户端加密数据,传递数据密文到服务端,服务端解密密文 输出明文

server // sdf_cpp_warpper.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // server端#ifndef UNICODE #define UNICODE #endif#define WIN32_LEAN_AND_MEAN#include <iostream> #include <string> #include <sstream> #include …

主进程中发生了一个javascript错误_知道html5 Web Worker标准吗?能实现JavaScript的多线程?

js为什么是单线程&#xff1f;主要是因为最开始javascript是单纯的服务于浏览器的一种脚步语言(那时候没有nodejs)。浏览器是为了渲染网页&#xff0c;通过dom与用户交互&#xff0c;如果一个线程需要给dom执行click事件&#xff0c;而另一个进程要删除这个dom&#xff0c;这2个…

C语言深度剖析书籍学习记录 第三章 预处理

宏 _LINE_ 表示正在编译的文件的行号_FILE_ 表示正在编译的文件的名字_DATE_ 表示编译时刻的日期字符串&#xff0c;例如: "25 Dec 2007"_TIME_ 表示编译时刻的时间字符串&#xff0c;例如: "12:30:55"_STDC_ 判断该文件是不是定义成标准 C 程序宏名的书写…

js正则限制字符串长度_正则笔记(3)万字长文,慎点。

正则讲了很久&#xff0c;也拖了很久&#xff0c;今天看看怎么用吧&#xff0c;后续更文应该会比较准勤快了。:-)书接上文【正则笔记(2)】。这次我们来看看正则的使用&#xff1a;(注&#xff1a;斜体表示为对应规则写出的正则表达式)一、 常用的正则表达式&#xff1a;1. 验证…

C语言深度剖析书籍学习记录 第四章 指针和数组

p 称为指针变量,p 里存储的内存地址处的内存称为 p 所指向的内存。 指针变量 p 里存储的任何数据都将被当作地址来处理一个基本的数据类型(包括结构体等自定义类型)加上“*” 号就构成了一个指针类型的模子。这个模子的大小是一定的&#xff0c;与“*”号前面的数据类型无 关。…

js中select下拉框重置_如何利用CSS3制作炫酷的下拉框

很多小伙伴都不清楚CSS3是做什么&#xff1f;用途是什么&#xff1f;接下来我就给展示一个css3制作一个炫酷下拉框。其实不只是这些&#xff0c;还有很多。CSS3是CSS(层叠样式表)技术的升级版本&#xff0c;于1999年开始制订&#xff0c;2001年5月23日W3C完成了CSS3的工作草案&…

select选择框必输校验_轮子这么多,我们为什么选择自研NewSQL

作者介绍李鑫&#xff0c;滴滴资深软件开发工程师&#xff0c;多年分布式存储领域设计及开发经验。曾参与NoSQL/NewSQL数据库Fusion、分布式时序数据库sentry、NewSQL数据库SDB等系统的设计开发工作。一、背景Fusion-NewSQL是由滴滴自研的在分布式KV存储基础上构建的NewSQL存储…