2020/2/20 Linux Socket编程 UDP协议 客户端

UDP协议

客户端

采用recv()、recvfrom()、send()、sendto()函数与服务器进行通信

注意:以上函数都是阻塞性函数

#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <memory.h>
#include <arpa/inet.h>
int sockfd;


int main(int argc, char *argv[])
{
	if(argc < 3){
		printf("usage: %s port\n", argv[0]);
		exit(1);	
	}

	//步骤1:创建套接字socket
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);//基于UDP用SOCK_DGRAM
	if(sockfd < 0){
		perror("socket error\n");
		exit(1);	
	}
	//步骤2:调用recvfrom和sendto等函数和服务器双向通信
	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;						 //ipv4
	serveraddr.sin_port = htons(atoi(argv[2]));  			 //port
	inet_pton(AF_INET, argv[1], &serveraddr.sin_addr.s_addr);//ip
	char buffer[1024] = "hello, This is client";
	if(sendto(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){
		perror("sendto error");
		exit(1);
	}	
	else{
		//接受服务器端发送的数据报文
		memset(buffer, 0, sizeof(buffer));
		size_t size;
		if((size = recv(sockfd, buffer, sizeof(buffer), 0)) < 0){//因为udp是无连接协议,所以不需要判断是否=0
				 //recvfrom()还要多发送方地址信息的2个参数,这里已经成功发送,所以recv即可
			perror("recv error");
			exit(1);		
		}
		else{
			printf("%s", buffer);
		}
	}
	close(sockfd);

	return 0;
}

结果

1. 也可以用send函数代替sento函数
如果用send也可以发送信息,但在此之前要调用connect进行连接

if(connect(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0){
		perror("connect error");
		exit(1);
	}	
	TCP中调用connect是三次握手,而在UDP中只是在内核中记录了服务器的ip、端口
	if(send(sockfd, buffer, sizeof(buffer), 0) < 0){
		perror("send error");
		exit(1);
	}	

如果不用connect,可能会接收到来自其他ip发来的信息~

2. 阻塞性函数有其缺陷

服务器刚打开,就会阻塞在recvfrom()中

如果用UDP进行传送,发送数据报文丢失,服务器就会一直阻塞在这里;客户端的收发也一样。

解决办法:

(1)超时控制,避免进程陷入无限期等待

#include <unistd.h>
unsigned int alarm(unsigned int seconds);

参数说明:要设定的定时时间,以秒为单位。在alarm调用成功后开始计时。超过该时间将触发SIGALRM信号

返回值:返回当前进程曾经设置的定时器剩余秒数。

(2)在套接字选项中设置超时控制

//设置套接字选项:使调用之前停掉的端口马上可以使用
	int ret;
	int opt = 1;
	if((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0){
		perror("setsockopt error");
		exit(1);
	}

应用程序通过创建一个linger结构来设置相应的操作特性:

struct linger {
    int l_onoff;
    int l_linger;
};

为了允许SO_LINGER,应用程序应将l_onoff设为非零,将l_linger设为零或需要的超时值(以秒为单位),然后调用setsockopt()。为了允许SO_DONTLINGER(亦即禁止SO_LINGER),l_onoff应设为零,然后调用setsockopt()。


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值