【C/C++套接字编程】套接字的基本概念与基础语法

news/2024/5/18 13:38:27 标签: 网络, 套接字编程, tcp/ip, udp

TCP/UDP实验为牵引,学习套接字编程的相关知识,再进一步深化对TCP/UDP的理解

目录

前言

Socket编程语法

1. 套接字及创建

什么是套接字?

创建套接字

2. 端口绑定

3. 收发信息

与recv()函数的比较:

与send()函数的比较:

编程实例 

总结


前言

计算机网络课学习了TCP/UDP相关的内容与知识,并组织了套接字实现TCP/UDP通信的实验。为了更好了解、掌握套接字编程的相关知识,特此做出总结。

参考文献

什么是套接字?Socket基本介绍_Ostrich5yw的博客-CSDN博客

套接字之读写:recvfrom()、read() 和sendto() 、write()_read和recvfrom_傻不拉几的程序员的博客-CSDN博客


Socket编程语法


1. 套接字及创建

什么是套接字?

套接字是一种通信机制(通信的两方的一种约定),socket屏蔽了各个协议的通信细节,提供了tcp/ip协议的抽象,对外提供了一套接口,同过这个接口就可以统一、方便的使用tcp/ip协议的功能。这使得程序员无需关注协议本身,直接使用socket提供的接口来进行互联的不同主机间的进程的通信。我们可以用套接字中的相关函数来完成通信过程。

套接字的特性有三个属性确定,它们是:域(domain),类型(type),和协议(protocol)。

:指定套接字通信中使用的网络介质。最常见的套接字域是 AF_INET(IPv4)或者AF_INET6(IPV6),它是指 Internet 网络

类型

流套接字(SOCK_STREAM): 流套接字用于提供面向连接、可靠的数据传输服务。该服务将保证数据能够实现无差错、无重复发送,并按顺序接收。流套接字之所以能够实现可靠的数据服务,原因在于其使用了传输控制协议,即TCP 数据报套接字(SOCK_DGRAM): 数据报套接字提供了一种无连接的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。数据报套接字使用UDP(User Datagram Protocol)协议进行数据的传输。 原始套接字(SOCK_RAW): 原始套接字与标准套接字(标准套接字指的是前面介绍的流套接字和数据报套接字)的区别在于:原始套接字可以读写内核没有处理的IP数据包,而流套接字只能读取TCP协议的数据,数据报套接字只能读取UDP协议的数据。因此,如果要访问其他协议发送数据必须使用原始套接字。

协议IPPROTO_TCPIPPROTO_UDP

创建套接字

int sockfd = socket(domain, type, protocol)

sockfd:套接字描述符,一个整数(如文件句柄) domain:整数,通信域,例如AF_INET(IPv4协议),AF_INET6(IPv6协议) type:通信类型 SOCK_STREAM:TCP(可靠,面向连接) SOCK_DGRAM:UDP(不可靠,无连接的) protocol: Internet协议(IP)的协议值,为0。这与出现在数据包IP报头的协议字段中的数字相同。(有关详细信息,请参见手动协议)


2. 端口绑定

套接字作为一层抽象,可以说是端口的代理人,主机用户只需要和本套接字进行交互,而不在意套接字的具体实现过程。因此,套接字创建完毕后,要和端口进行绑定,之后的信息流进流出端口,其复杂的过程就被抽象为与套接字这个代理人的交互过程了。

自然要知道绑定的端口的地址,可以通过如下设置

struct sockaddr_in client_in;
client_in.sin_port =htons(20001);//端口号20001
client_in.sin_addr.S_un.S_addr = inet_addr("10.128.18.146");//ipv4地址
client_in.sin_family =AF_INET;//选择ipv4协议簇

这个绑定过程,我们通过bind()来实现。

bind():

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

首先如上设置IP/Port信息,接下来将创建的套接字与之进行绑定

//part3 将用户端的socket和用户端的ip地址和端口号绑定
if (bind(socket_client, (struct sockaddr *)&client_in, sizeof(client_in)) == SOCKET_ERROR)
{
    printf("blind() Failed:%d\\n", WSAGetLastError());        
    return USER_ERROR;
}

3. 收发信息

1、read() 和write()

#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0。
ssize_t write(int fd, const void *buf, size_t count);
如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中。

流字节套接字(例如TCP套接字)上的read和write函数所表现的行为不同于通常的文件I/O。字节流套接字上调用read或write输入或输出的字节数可能比请求的数量少(我们称之为部分读和部分写),然而这不是出错的状态。这个现象的原因在于内核中用于套接字的缓冲区可能已达到了极限。此时所需要的是调用者再次调用read或write函数,以输入或输出剩余的字节

2、recvfrom()和sendto() recvfrom()从(已连接)套接口上接收数据,并捕获数据发送源的地址。对于SOCK_STREAM类型的套接口,最多可接收缓冲区大小个数据。对于数据报类套接口,队列中第一个数据报中的数据被解包,但最多不超过缓冲区的大小。如果数据报大于缓冲区,那么缓冲区中只有数据报的前面部分,其他的数据都丢失了,并且recvfrom()函数返回WSAEMSGSIZE错误。

SendTo指向一指定目的地发送数据,sendto()适用于发送(未建立连接)的UDP数据包 (参数为SOCK_DGRAM)。

int recvfrom(SOCKET s,void *buf,int len,unsigned int flags, struct sockaddr *from,int *fromlen);
参数:
s:       标识一个已连接套接口的描述字。
buf:     接收数据缓冲区。
len:     缓冲区长度。
flags:   调用操作方式。
from:   (可选)指针,指向装有源地址的缓冲区。
fromlen:(可选)指针,指向from缓冲区长度值。
若无错误发生,recvfrom()返回读入的字节数。如果连接已中止,返回0。否则的话,返回SOCKET_ERROR错误,应用程序可通过WSAGetLastError()获取相应错误代码。
int sendto (IN SOCKET s, IN const char FAR * buf, IN int len, IN int flags, IN const struct sockaddr FAR *to, IN int tolen);
参数:
s        套接字
buff     待发送数据的缓冲区
size     缓冲区长度
Flags    调用方式标志位, 一般为0, 改变Flags,将会改变Sendto发送的形式
addr    (可选)指针,指向目的套接字的地址
len addr 所指地址的长度
返回值为整型,如果成功,则返回发送的字节数,失败则返回SOCKET_ERROR。

与recv()函数的比较:

UDP使用recvfrom()函数接收数据,他类似于标准的read(),但是在recvfrom()函数中要指明目的地址。从套接字上接收一个消息。对于recvfrom ,可同时应用于面向连接的和无连接的套接字。recv一般只用在面向连接的套接字,几乎等同于recvfrom,只要将recvfrom的第五个参数设置NULL。不管是recv还是recvfrom,都有两种模式,阻塞和非阻塞,可以通过ioctl函数来设置。阻塞模式是一直等待直到有数据到达,非阻塞模式是立即返回,需要通过消息,异步事件等来查询完成状态。

recv函数

int recv( SOCKET s, char *buf, int len, int flags)

**功能:**不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据。

参数一:指定接收端套接字描述符; 参数二:指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据; 参数三:指明buf的长度; 参数四 :一般置为0。


与send()函数的比较:

是向一个已经连接的socket发送数据,而sendto则是面向未建立连接的UDP数据报。不论是客户端还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

send函数

int send( SOCKET s,char *buf,int len,int flags );

功能:不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据。客户程序一般用send函数向服务器发送请求,而服务器则通常用send函数来向客户程序发送应答。

参数一:指定发送端套接字描述符; 参数二:存放应用程序要发送数据的缓冲区; 参数三:实际要发送的数据的字节数; 参数四:一般置为0。


编程实例 

【C/C++套接字编程】TCP协议通信的简单实现_Mr_Fmnwon的博客-CSDN博客 

【C/C++套接字编程】UDP协议通信的简单实现_Mr_Fmnwon的博客-CSDN博客 

结合起来食用最佳 


总结

关于TCP/UDP的实验实例,将在新的博客中给出。


http://www.niftyadmin.cn/n/441893.html

相关文章

从零开始搭建群众权益平台(四)

这篇博客我们可以添加以下功能以进一步提高我们的应用程序的复杂性和密码找回的功能性&#xff1a; 复杂的权限控制&#xff1a; 对于更复杂的权限控制&#xff0c;我们可能需要引入新的数据模型来管理角色和权限。例如&#xff0c;我们可以创建一个Role模型和一个Permission…

CAP原则理解

CAP原则概述 C&#xff1a;Consistency&#xff08;一致性&#xff09;A&#xff1a;Availability&#xff08;可用性&#xff09;P&#xff1a;Partition tolerance&#xff08;分区容错性&#xff09; CAP原则是分布式系统设计的重要原则&#xff0c;其具体含义是指在一个分…

Hibernate框架【一】——HIbernate框架介绍

系列文章目录 Hibernate框架【三】——基本映射——一对一映射 Hibernate框架【四】——基本映射——多对一和一对多映射 Hibernate框架【五】——基本映射——多对多映射 Hibernate框架介绍 系列文章目录前言一、什么是HIbernate框架Hibernate架构图Hibernate提供的核心功能和…

Python Crc32 介绍

文章目录 CRC32 介绍Python CRC32 本篇文章将介绍使用 Python 中的 binascii 或 zlib 库计算数据的 crc32。 CRC32 介绍 CRC32&#xff08;Cyclic Redundancy Check&#xff09;是一种循环冗余校验算法&#xff0c;常用于数据传输中的差错检测。它通过计算数据的校验值来检测数…

HJ26 字符串排序

题目&#xff1a; HJ26 字符串排序 题解&#xff1a; 规则 1 &#xff1a;英文字母从 A 到 Z 排列&#xff0c;不区分大小写。 统一转换&#xff0c;通过减去对应字母的起始值&#xff0c;得到一个相对值&#xff0c;抹平大小写&#xff0c;例如&#xff1a;B - A&#xff…

Linux工具之gdb(含移植到arm-linux系统)

文章目录 文件目录结构移植ncurses库移植gdb移植到arm板调试测试 linux主机&#xff1a;ubuntu-18.04 交叉编译器&#xff1a;arm-buildroot-linux-gnueabihf 开发板kernel&#xff1a;Linux 5.4.0-150-generic x86_64 开发板&#xff1a;100ASK_STM32MP157_PRO开发板 arm-…

B046-cms01-后台搭建 界面修改 分页 GirdManager

目录 cms项目介绍Maven跳转到后台首页视图解析器页面和静态资源准备资源分布controller控制器 跳转到文章展示页面index.JSPArticleControllerarticle.jsp gridManager初体验和显示文章数据时间和是否启用显示Articlearticle.jsp 展示文章类型ArticleServiceImplarticle.jsp 按…

苹果iOS 17新功能:iPhone激活Apple Watch铃声反向查找手表

苹果 Apple Watch 此前一直有查找 iPhone 的功能&#xff0c;用户可以点击表盘的电话图标&#xff08;或者长按&#xff09;来激活 iPhone 的铃声&#xff0c;从而找到附近的 iPhone 手机。 在最新的 iOS 17 测试版本中&#xff0c;苹果为 iPhone 也添加了这一功能的反向版本&a…