Linux下的TCP/IP编程----UDP实践篇

大部分的准备工作的代码都合之前TCP时候的一样,我们只需要在关键部分进行一下修改即可。

首先是服务端的程序:

创建套接字—-绑定地址—-进行通讯

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUFF_SIZE 30

void error_handling(char *message);

int main (int argc ,char *argv[]){

      //客户端和服务端的socket描述符
    int  serv_sock;
    //客户端和服务端的地址
    struct sockaddr_in serv_addr;
    struct sockaddr_in clent_addr;

    //客户端地址大小
    socklen_t  client_addr_size;

    //要发送的消息
    char messages [BUFF_SIZE];
    //字符串长度
    int str_len = 0;

    if(argc!=2){
        printf("Usage : %s  <port> \n",argv[0]);
        exit(1);
    }

    //在创建socket的时候需要指定连接方式为面向消息的
    serv_sock = socket(PF_INET,SOCK_DGRAM,0);
    //进行检查
    if(serv_sock == -1){
        error_handling("UDP socket creation error");
    }
    //
    memset(&serv_addr,0,sizeof(serv_addr));

    //为serve_addr结构体设置使用协议,IP地址,端口号
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(atoi(argv[1]));
    //进行地址绑定
    if(bind(serv_sock,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) == -1){
        error_handling("bind() error");
    }

    while(1){
        client_addr_size = sizeof(clent_addr);
        str_len = recvfrom(serv_sock,messages,BUFF_SIZE,0,(struct sockaddr *) &clent_addr,&client_addr_size);

        sendto(serv_sock,messages,str_len,0,(struct sockaddr *) &clent_addr,client_addr_size);

    }

    close(serv_sock);
return 0;
}

void error_handling(char * message){
    fputs(message,stderr);
    fputc('\n',stderr);
    exit(1);
}

然后是客户端程序:

创建套接字—-进行通信

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>

#define BUFF_SIZE 30

void error_handling(char *messages);

int main (int argc ,char * argv[]){
    //本地的socket
    int sock;
    //要传输的消息
    char message[BUFF_SIZE];
    //保存消息的长度
    int str_len;
    //socket地址的长度
    struct sockaddr_in  server_addr;
    struct sockaddr_in  from_addr;

    socklen_t addr_size;
  //检查参数的个数
    if(argc != 3){
        printf("Usage : %s  <port> \n",argv[0]);
        exit(1);
    }

      //创建客户端的socket,并指定使用协议,连接方式。
    sock  = socket(PF_INET,SOCK_DGRAM,0);
    //初始化server_addr所申请的内存空间
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    while(1){
        fputs("Insert message ( q to quit ):",stdout);
        fgets(message,sizeof(message),stdin);

        //接收到结束输入的字符
        if(!strcmp(message,"q\n") || !strcmp(message,"Q\n")){
            break;
        }

        sendto(sock,message,strlen(message),0,(struct sockaddr *) &server_addr,sizeof(server_addr));
        addr_size = sizeof(from_addr);

        str_len = recvfrom(sock,message,BUFF_SIZE,0,(struct sockaddr *)&from_addr,&addr_size);

        message[str_len] = 0;
        printf("Message from server : %s\n",message);
    }

    close(sock);

    return 0;
}

void error_handling(char * message){
    fputs(message,stderr);
    fputc('\n',stderr);
    exit(1);
}

至此我们就完成了一个基于UDP的服务端/客户端程序,我们可以对其进行编译运行,查看一下效果。

注意点:

  1. 我们在编写UDP的客户端时并没有直接给他指定IP地址和端口号,但是在运行时没有任何的错误。这是因为本应该在sendto()函数之前进行地址绑定的,也就是调用bind()函数,但是我们在书写时省略了,当调用sendto函数时系统发现尚未分配地址信息,就会随机的为其分配一个IP地址和端口号(IP地址用主机的IP地址,端口号使用尚未使用的端口号),所以无需进行额外的配置。

  2. 已连接套接字和未连接套接字:
    在每次调用sendto()函数的时候都会重复一下的三个步骤:1. 向UDP套接字注册目标IP地址和端口号;2. 传输数据 3.清除UDP套接字中注册的目标地址信息。
    这个机制很好的保证了UDP套接字的重复使用,使得只需要创建一个套接字便可以和许多的主机进行通讯。但是也有其缺点,就是当只是进行点对点的通讯时每次都需要经历一次创建过程,但是地址信息并没有发生变化,所以是无效的。为此产生了一个新的UDP套接字,他和一般的套接字唯一的区别在于他的目标信息是不发生变化的,这样就可以避免了多次无效的创建。

创建方法:

 //创建客户端的socket,并指定使用协议,连接方式。
    sock  = socket(PF_INET,SOCK_DGRAM,0);
    //初始化server_addr所申请的内存空间
    memset(&server_addr,0,sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(argv[1]);
    server_addr.sin_port = htons(atoi(argv[2]));

    //添加上connect()函数,使其成为已连接的套接字
    connect(sock,(struct sockaddr *) &server_addr,sizeof(server_addr));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值