网络编程之数据包套接字

数据报套接字提供一种无连接、不可靠的服务。该服务并不能保证数据传输的可靠性,数据有可能在传输过程中丢失或出现数据重复,且无法保证顺序地接收到数据。使用UDP协议进行数据的传输。

服务端代码

//服务端
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main(int argc, char* argv[]) {
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    
    SOCKET sockServer = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockServer==INVALID_SOCKET)//如果套接字创建失败,则打印错误信息并退出程序。
	{
		printf("sock error!");
		return 0;
	}

	SOCKADDR_IN addrServer;
    addrServer.sin_addr.s_addr = INADDR_ANY;
    addrServer.sin_family = AF_INET;
    addrServer.sin_port = htons(6000);
    
    if(bind(sockServer, (SOCKADDR*)&addrServer, sizeof(SOCKADDR))==SOCKET_ERROR)//如果绑定失败,则打印错误信息并退出程序。
	{
		printf("bind error!");
		closesocket(sockServer);
		return 0;
	}

    SOCKADDR_IN addrClient;
	int len=sizeof(addrClient);
	while(true)
	{
		char recvData[255];
		int  ret=recvfrom(sockServer,recvData,255,0,(sockaddr *)&addrClient,&len);//接收来自客户端的UDP数据包
		if (ret>0)
		{
			recvData[ret]=0x00;
			printf("接收到一个连接:%s\r\n",inet_ntoa(addrClient.sin_addr));
			printf(recvData);//将接收到的数据打印出来
		}

		char * sendData="一个来自服务端的UDP数据包\n";//向客户端发送一个消息
		sendto(sockServer,sendData,strlen(sendData),0,(sockaddr *)&addrClient,len);
	}

    closesocket(sockServer);//关闭服务端监听套接字
    WSACleanup();

    printf("success!\n");//表示正常运行
    return 0;
}

客户端代码 

//客户端
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")
int main(int argc, char* argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2),&wsaData);

SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);

//设置要连接的服务端的地址信息
SOCKADDR_IN addrServer;
addrServer.sin_family=AF_INET;
addrServer.sin_addr.s_addr=inet_addr("127.0.0.1");
addrServer.sin_port=htons(6000);
int tolen=sizeof(addrServer);

char * sendData="一个来自客户端的UDP数据包\n";
sendto(sockClient,sendData,strlen(sendData),0,(sockaddr *)&addrServer,tolen);

char recvData[255];
int ret = recvfrom(sockClient,recvData,255,0,(sockaddr *)&addrServer,&tolen);
if(ret>0)
{
	recvData[ret]=0x00;
	printf(recvData);
}
closesocket(sockClient);
WSACleanup();

printf("success!\n");
return 0;
}

先运行服务端,然后运行客户端

服务端结果如下

客户端结果如下

1、数据包套接字相较于流式套接字特有的两个函数

recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen)

s: 套接字描述符,指定要接收数据的套接字。

buf: 指向存放接收数据的缓冲区。

len: 缓冲区的大小,即最大接收数据的长度。

flags: 接收操作的标志,通常设置为0。

from: 指向一个 struct sockaddr 类型的指针,用于存放发送数据的地址信息。

len: 一个指向整型变量的指针,用于指定 from 缓冲区的大小

sendto(SOCKET s,char *buf,int datalen,int flags,sockaddr *to,int tolen)

s: 套接字描述符,指定要发送数据的套接字。

buf: 指向待发送数据的缓冲区。

datalen: 待发送数据的长度。

flags: 发送操作的标志,通常设置为0。

to: 指向一个sockaddr 类型的指针,包含目标地址信息。

len: to缓冲区的大小

2、数据包套接字有两种模式

对等模式

Socket()-->bind()-->recvfrom()-->sendto()-->close()

Socket()-->bind()-->recvfrom()-->sentdo()-->close()

非对等模式(C/S模式)

Socket()-->bind()-->recvfrom()-->sendto()-->close()

Socket()-->sentdo()-->recvfrom()-->close()

跟流式套接字对比,服务器端少了listen()和accept(),客户端少了connect()

C/S模式的无连接套接字编程模型具有以下特点。

(1)应用程序双方是不对等的,服务器要先行启动,处于被动的等待访问的状态,而客户机则可以随时主动地请求访问服务器。两者在进行网络通信时,服务器要经过创建套接字、绑定套接字、交换数据和关闭套接字4个阶段,而客户机不需要进行套接字的绑定。

(2)服务器进程将套接字绑定到众所周知的端口,或事先指定的端口,并且,客户机端必须确切地知道服务器端套接字使用的网络地址。

(3)客户机端套接字使用动态分配的自由端口,不需要进行绑定,服务器端事先也不必知道客户机端套接字使用的网络地址。

(4)客户机端必须首先发送数据报,并在数据报中携带双方的地址;服务器端收到后,才能知道客户机端的地址,才能给客户机端回送数据报。

(5)服务器可以接收多个客户机端的数据。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Genius256

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值