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_TCP
,IPPROTO_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
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.fwqtg.net