Linux网络编程:基于UDP的程序开发回顾篇

基于无连接的UDP程序设计

同样,在开发基于UDP的应用程序时,其主要流程如下:

对于面向无连接的UDP应用程序在开发过程中服务端和客户端的操作流程基本差不多。对比面向连接的TCP程序,服务端少了listen和accept函数。前面我们也说过listen函数最主要的作用就是将一个socket套接字描述符转为被动监听模式,然后调用accept主要是用于等待客户端(用connect)来连接服务器。connect函数不仅可以用于流式套接字还可用于数据报式套接字。在TCP中,客户端调用connect函数会向服务器端触发一个TCP的3次握手过程,去建立一条TCP连接;而在UDP中,客户端调用该函数主要的作用是告诉后面将要调用的recvfrom函数,仅仅只接受在connect函数中指明的服务器发来的数据,这样当后面调用recvfrom时最后两个参数就可以置为NULL了。也就说对UDP编程来说,客户端调用connect是可选的:如果调用了connect函数,recvfrom就可以省掉最后两个参数;如果不调用connect则recvfrom必须指明从哪儿收数据。

对于UDP的编程其实主要在数据的收发处理上,而面向无连接的UDP编程中收发数据用到的最多的函数就是recvfrom()和sendto(),其原型如下:

ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);

ssize_t sendto(int s, const void *buf, size_t len, int flags, struct sockaddr *to, socklen_t tolen);

recvfrom函数主要用于从s所指定的套接字中接收数据,并将其存储在buf所指向的缓冲区里。如果from参数不为NULL,那么其中便会携带消息发送端的地址信息,fromlen则指明了信息发送方地址信息结构体的大小。如果接收方对发送发的地址不感兴趣,将from和fromlen置为NULL即可。返回值:小于0,有错误;大于0,实际收到的字节数;等于0,对端主动关闭。

sendto函数,主要是buf所指向的数据发送到套接字描述符s中,len为要发送的数据长度,to中存储了对端的地址信息,即数据该发往何处,tolen为to所占的字节数。返回值:小于0,有错误;大于0,实际发送的字节数。

另外我们还知道,sendto是可以用于面向连接的流式套接字的,在TCP开发章节我们已经提过。这里在罗嗦一点,如果sendto用于面向流式的套接字编程中,to和tolen参数都会被忽略,如果发送数据时连接还未建立相应的提示错误为ENOTCONN。

这里也没有哪个规定说是不准在TCP程序中用sendto,但我们一般都不这么做,自己体会一下就明白了,除非你的项目开发中有特殊需求必须用。一句话:记住sendto和recvfrom既可以用于面向连接的流式套接字中收发数据,也可以用于面向无连接的数据报式套接字。sendto()和recvfrom()一般用在面向无连接的数据报式套接字的程序开发中。

  UDP服务端代码, server.cpp

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define MAX_MSG_SIZE 1024

int main(int argc,char** argv){
    int skfd,addrlen,ret;
    struct sockaddr_in addr,cltaddr;
    char buf[MAX_MSG_SIZE]={0};
    char sndbuf[MAX_MSG_SIZE]={0};

    //创建数据报式套接字skfd
    if(0>(skfd=socket(AF_INET,SOCK_DGRAM,0))){
         perror("Create Error");
         exit(1);
    }

    bzero(&addr,sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr=htonl(INADDR_ANY);
    addr.sin_port=htons(atoi(argv[1]));

    //将socket文件描述符skfd和本地端口和地址绑定起来
    if(0>(bind(skfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in)))){
         perror("Bind Error");
         exit(1);
    }

    //开始收发数据
    while(1){
         ret=recvfrom(skfd,buf,MAX_MSG_SIZE,0,(struct sockaddr*)&cltaddr,&addrlen);
         if(ret < 0){
            printf("recv data from %s:%d error!",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port));
         }else if(ret == 0){
            perror("client has been closing socket!");
         }else{
            printf("From %s:%d,%s",inet_ntoa(cltaddr.sin_addr),ntohs(cltaddr.sin_port),buf);
            memset(sndbuf,0,MAX_MSG_SIZE);
            switch(buf[0]){
                  case ‘a‘:
                       strcpy(sndbuf,"After u ,lady...");
                  break;
                  case ‘b‘:
                       strcpy(sndbuf,"Before u ,sir...");
                  break;
                  case ‘c‘:
                       strcpy(sndbuf,"Can u?");
                       break;
                  default:
                       strcpy(sndbuf,"I dont‘t know what u want!");
            }
            sendto(skfd,sndbuf,strlen(sndbuf),0,(struct sockaddr*)&cltaddr,addrlen);
         }
         memset(buf,0,MAX_MSG_SIZE);
    }
    return 0;
}

  UDP客户端代码, client.cpp

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>
#define MAX_MSG_SIZE 1024

int main(int argc,char** argv){
    int skfd,ret,len;
    struct sockaddr_in srvaddr;
    char buf[MAX_MSG_SIZE]={0};
    char sndbuf[MAX_MSG_SIZE]={0};
    struct in_addr addr;

    //创建数据报式套接字skfd
    if(0>(skfd=socket(AF_INET,SOCK_DGRAM,0))){
         perror("Create Error");
         exit(1);
    }

    if(0 == inet_aton(argv[1],&addr)){
         perror("server addr invalid!");
         exit(1);
    }

    bzero(&srvaddr,sizeof(struct sockaddr_in));
    srvaddr.sin_family = AF_INET;
    srvaddr.sin_addr=addr;
    srvaddr.sin_port=htons(atoi(argv[2]));

    //我们的客户端只接收从服务器地址是srvaddr的主机发来的数据
    if(0>(connect(skfd,(struct sockaddr*)&srvaddr,sizeof(struct sockaddr_in)))){
          perror("Connect Error");
          exit(1);
    }

    //开始收发数据
    while(1){
        memset(sndbuf,0,MAX_MSG_SIZE);
        len=read(0,sndbuf,MAX_MSG_SIZE);
        ret=sendto(skfd,sndbuf,strlen(sndbuf),0,(struct sockaddr*)&srvaddr,sizeof(struct sockaddr));
        if(ret == len){
              memset(buf,0,MAX_MSG_SIZE);
              //我们已经知道服务器地址信息了,所以最后两个参数为NULL
              ret=recvfrom(skfd,buf,MAX_MSG_SIZE,0,NULL,NULL);

              if(ret < 0){
                     perror("read error from server!");
              }else if(ret == 0){
                     perror("server has been closing socket!");
              }else{
                     buf[ret]=‘\0‘;
                     printf("From Server:%s\n",buf);
              }
        }
    }
    return 0;
}

  测试结果:

我们客户端接收用户命令行输入的指令,然后将其发给UDP服务器端;服务器端收到不同的指令后给客户端予以不同的提示信息,整个流程如上所示。

udpclt.c的示例代码中我是调用了connect,勤奋好学的童鞋可以动手试验哈不调用connect然后将程序调通吧。

  转载自:http://blog.chinaunix.net/uid-23069658-id-3276167.html

时间: 2024-12-22 13:05:06

Linux网络编程:基于UDP的程序开发回顾篇的相关文章

linux网络编程 基于TCP的程序开发

面向连接的TCP程序设计 基于TCP的程序开发分为服务器端和客户端两部分,常见的核心步骤和流程: 其实按照上面这个流程调用系统API确实可以完全实现应用层程序的开发,一点问题没有.可随着时间的推移,你会觉得这样子的开发毫无激情.为什么TCP的开发就要按照这样的流程来呢?而且一般出的问题几乎都不在这几个系统调用上,原因何在?当我们弄清网络开发的本质,协议栈的设计原理.数据流向等这些问题的答案也就会慢慢浮出水面了.接下来这几篇博文主要是围绕网络编程展开,目的是引出后面对于Linux下TCP/IP协议

linux网络编程笔记——UDP

目前这部分代码会出现阻塞问题,暂时尚未解决 #include "udp.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <malloc.h> #include <sys/types.h> #include <sys/socket

Java网络编程 - 基于UDP协议 实现简单的聊天室程序

最近比较闲,一直在抽空回顾一些Java方面的技术应用. 今天没什么事做,基于UDP协议,写了一个非常简单的聊天室程序. 现在的工作,很少用到socket,也算是对Java网络编程方面的一个简单回忆. 先看一下效果: 实现的效果可以说是非常非常简单,但还是可以简单的看到一个实现原理. "聊天室001"的用户,小红和小绿相互聊了两句,"聊天室002"的小黑无人理会,在一旁寂寞着. 看一下代码实现: 1.首先是消息服务器的实现,功能很简单: 将客户端的信息(进入了哪一个聊

JAVA基础知识之网络编程——-基于UDP协议的通信例子

UDP是一种不可靠的协议,它在通信两端各建立一个socket,这两个socket不会建立持久的通信连接,只会单方面向对方发送数据,不检查发送结果. java中基于UDP协议的通信使用DatagramSocket类的receive和send方法即可,但消息需要通过一个特定的类封装(DatagramPacket) 下面是一个基于UDP协议的通信的例子, 服务器端, 1 package udp; 2 3 import java.io.IOException; 4 import java.net.Dat

网络编程——基于UDP的网络化CPU性能检测

网络化计算机性能检测软件的开发,可对指定目标主机的CPU利用率进行远程检测,并自动对远程主机执行性能指标进行周期性检测,最终实现图形化显示检测结果. 网络通信模块:(客户端类似,因为udp是对等通信) 启动服务器:创建套接字并注册网络事件 void CRemoteCPUImitateDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 int Ret; char BufferData[2000] = { 0 }; int ClientAddrSize =

Linux网络编程--聊天室客户端程序

聊天室客户端程序 #define _GNU_SOURCE 1 #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <string.h> #in

linux网络编程--tcp/udp编程模型

tcp 模型如下: 上面的模型已经很清楚了 具体函数用法就不细说了 请看tcp简单的例子: 其中server.c #include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/socket.h>#include <sys/types.h>#include <netinet/in.h>#include <arpa/inet.h> #define e

网络编程: 基于UDP协议的socket

udp是无链接的,启动服务之后可以直接接受消息,不需要提前建立链接 UDP协议的通信优势: 允许一个服务器同时和多个客户端通信, TCP不行 原文地址:https://www.cnblogs.com/niuli1987/p/9470035.html

java 网络编程 基于UDP协议的通信

使用UDP协议,写一个能在同一界面发送消息,并显示消息的聊天软件. 代码实现如下: package com.abel.socket; import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.util.Scanner; /* * 多线程在一个界面同时完成发送接收 * 1 发送send * ***创建