[C语言]一个很实用的服务端和客户端进行UDP通信的实例

前段时间发了个TCP通信的例子,现在再来一个UDP通信的例子。这些可以作为样本程序,用到开发中。“裸写”socket老是记不住步骤,经常被鄙视……

下面的例子很简单,写一个UDP的server用于收包,写一个UDP的client用于发包并接收来自server的回复。其中UDP的client写了两个,一个是不需要connect的,另一个是带上connect的,两个client实现的功能是一样的。从效率上,带上connect的UDP肯定效率稍微高一些。不过UDP的connect和TCP里面非常不一样。在UDP里面connect的时候并没有三次握手的过程,但是它指定了与自己通信的对方的具体地址,内核中会将次地址记录下来,如果你的UDP就是在确定了两台机器之间传送信息,建议选取带有connect的套接字。connect之后与对方通信直接write或者read函数就可以,不用再指定对方ip和port,并且connect之后的套接字可以自动过滤掉不是来自指定通信方的信息。UDP可以调用多次connect函数,但是TCP套接字只能调用一次,再次调用会出现错误。

1. 首先是服务端的程序:

UDPserver.cpp

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <sys/socket.h>
 6 #include <stdlib.h>
 7 #include <netinet/in.h>
 8 #include <arpa/inet.h>
 9
10 #define PORT 1234
11 #define MAXDATASIZE 100
12
13 int main(void)
14 {
15     int sockfd;
16     struct sockaddr_in server;
17     struct sockaddr_in client;
18     socklen_t len;
19     int num;
20     char buf[MAXDATASIZE];
21     if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
22     {
23         perror("Creating socket failed.\n");
24         exit(1);
25     }
26     bzero(&server, sizeof(server));
27     server.sin_family = AF_INET;
28     server.sin_port = htons(PORT);
29     server.sin_addr.s_addr = htonl(INADDR_ANY);
30     if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
31     {
32         perror("Bind() error.\n");
33         exit(1);
34     }
35
36     len = sizeof(client);
37     while(1)
38     {
39         num = recvfrom(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&client, &len);
40         if(num < 0)
41         {
42             perror("recvfrom() error.\n");
43             exit(1);
44         }
45         buf[num] = ‘\0‘;
46         printf("You got a message <%s> from client. \nIt‘s ip is %s, port is %d. \n", buf, inet_ntoa(client.sin_addr),htons(client.sin_port));
47         sendto(sockfd, "Welcome\n", 8, 0, (struct sockaddr *)&client, len);
48         if ( !strcmp(buf, "bye") ){
49             break;
50         }
51     }
52     close(sockfd);
53 }

2. 然后,我们给出带有connect的客户端程序:

UDPclientWithConnect.cpp

 1 #include <stdio.h>
 2 #include <stdlib.h>
 3 #include <unistd.h>
 4 #include <string.h>
 5 #include <sys/types.h>
 6 #include <sys/socket.h>
 7 #include <netinet/in.h>
 8 #include <netdb.h>
 9 #include <arpa/inet.h>
10
11 #define PORT 1234
12
13 #define MAXDATASIZE 100
14
15 int main(int argc, char *argv[])
16 {
17     int sockfd, num;
18     char buf[MAXDATASIZE];
19     struct hostent *he;
20     struct sockaddr_in server, peer;
21     if(argc != 3)
22     {
23         printf("Usage: %s <IP address> <message>\n", argv[0]);
24         exit(1);
25     }
26
27     if((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1)
28     {
29         printf("socket() error\n");
30         exit(1);
31     }
32     bzero(&server, sizeof(server));
33     server.sin_family = AF_INET;
34     server.sin_port = htons(PORT);
35
36     server.sin_addr.s_addr = inet_addr(argv[1]);
37     //server.sin_addr.s_addr = inet_addr(argv[1]);
38     if(connect(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
39     {
40         printf("connect() error.\n");
41         exit(1);
42     }
43
44     send(sockfd, argv[2], strlen(argv[2]), 0);
45
46     while(1)
47     {
48         if((num = recv(sockfd, buf, MAXDATASIZE, 0)) == -1)
49         {
50             printf("recv() error.\n");
51             exit(1);
52         }
53
54         buf[num] = ‘\0‘;
55         printf("Server Message: %s.\n", buf);
56         break;
57     }
58     close(sockfd);
59 }

3. 最后,再给一个不带connect的客户端程序。

UDPclientNoConnect.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define PORT 1234

#define MAXDATASIZE 100

int main(int argc, char *argv[])
{
    int sockfd, num;
    char buf[MAXDATASIZE];
    struct hostent *he;
    struct sockaddr_in server, peer;
    if(argc != 3)
    {
        printf("Usage: %s <IP address> <message>\n", argv[0]);
        exit(1);
    }
    if((he = gethostbyname(argv[1]))==NULL)
    {
        printf("gethostbyname() error\n");
        exit(1);
    }
    if((sockfd=socket(AF_INET, SOCK_DGRAM, 0)) == -1)
    {
        printf("socket() error\n");
        exit(1);
    }
    bzero(&server, sizeof(server));
    server.sin_family = AF_INET;
    server.sin_port = htons(PORT);
    server.sin_addr = *( (struct in_addr *)he->h_addr);
    sendto(sockfd, argv[2], strlen(argv[2]), 0, (struct sockaddr *)&server, sizeof(server));
    socklen_t len;
    len = sizeof(server);
    while(1)
    {
        if((num = recvfrom(sockfd, buf, MAXDATASIZE, 0, (struct sockaddr *)&peer, &len)) == -1)
        {
            printf("recvfrom() error\n");
            exit(1);
        }
        if(len != sizeof(server) || memcmp((const void *)&server, (const void *)&peer, len) != 0 )
        {
            printf("Receive message from other server.\n");
            continue;
        }
        buf[num] = ‘\0‘;
        printf("Server Message: %s.\n", buf);
        break;
    }
    close(sockfd);
}

执行一下命令进行编译:

$ g++ -o UDPserver UDPserver.cpp

$ g++ -o UDPclient2 UDPclientWithConnect.cpp

$ g++ -o UDPclient1 UDPclientNoConnect.cpp

完了以后就看到三个可执行文件了。

打开一个命令行,执行./UDPserver启动服务端程序,再打开另外一个命令行,执行./UDPclient1 127.0.0.1 "nihaonihao"或者./UDPclient2 127.0.0.1 "testtest"即可查看到以下效果:

[[email protected] ~/Cprog/udpCSmodel]$ ./UDPserver
You got a message <nihaonihao> from client.
It‘s ip is 127.0.0.1, port is 25595.
You got a message <testtest> from client.
It‘s ip is 127.0.0.1, port is 27396. 
[[email protected] ~/Cprog/udpCSmodel]$ ./UDPclient1 127.0.0.1 "nihaonihao"
Server Message: Welcome
.
[[email protected] ~/Cprog/udpCSmodel]$ ./UDPclient2 127.0.0.1 "testtest"
Server Message: Welcome
.
[[email protected] ~/Cprog/udpCSmodel]$ 

最后再来解释一个带有connect的UDP的好处。由于UDP是不可靠传输,如果我发了数据出去,对方其实服务器是关闭的,这时会有什么结果呢?对于刚才的UDPclient1,也就是不带connect的,客户端程序会卡在recvfrom这里,因为对方是关闭的,它永远也收不到来自对方的回包。但是对于UDPclient2,也就是带有connect,我们其实可以收到一个错误,并设置errno(errno:111,connection refused)。这样看上去就比卡死在那里友好多了。对于这个问题的具体分析可以参考这篇文章:

UDP怎么会返回Connection refused错误

[[email protected] ~/Cprog/udpCSmodel]$ ./UDPclient2 127.0.0.1 "testtest"
recv() error.
[[email protected] ~/Cprog/udpCSmodel]$ ./UDPclient1 127.0.0.1 "testtest"
 #注释:程序在这里卡死
时间: 2024-07-30 10:19:51

[C语言]一个很实用的服务端和客户端进行UDP通信的实例的相关文章

[C语言]一个很实用的服务端和客户端进行TCP通信的实例

本文给出一个很实用的服务端和客户端进行TCP通信的小例子.具体实现上非常简单,只是平时编写类似程序,具体步骤经常忘记,还要总是查,暂且将其记下来,方便以后参考. (1)客户端程序,编写一个文件client.c,内容如下: #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/types.h> #include <

编写一个简单的TCP服务端和客户端

下面的实验环境是linux系统. 效果如下: 1.启动服务端程序,监听在6666端口上  2.启动客户端,与服务端建立TCP连接  3.建立完TCP连接,在客户端上向服务端发送消息 4.断开连接 实现的功能很简单,但是对于初来乍到的我费了不少劲,因此在此总结一下,如有错点请各位大神指点指点 什么是SOCKET(套接字): 百度的解释是:网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 将计算机比作酒店,那么通过IP寻找主机,就好比通过地址寻址酒店.通过端

java 界面编程用socket实现服务端与客户端的循环通信。

服务端: package 实验五聊天; import java.awt.BorderLayout; import java.awt.EventQueue; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.ne

关于一个WCF调用的服务端和客户端的配置信息集合

客户端的配置我知道. 但是: httpTransport maxReceivedMessageSize="2147483647" <dataContractSerializer maxItemsInObjectGraph="2147483647"/> <httpRuntime maxRequestLength="2097151"/> 上述三个还真没有如何用过! http://www.cnblogs.com/xuezhi/a

基于SignalR的服务端和客户端通讯处理

SignalR是一个.NET Core/.NET Framework的实时通讯的框架,一般应用在ASP.NET上,当然也可以应用在Winform上实现服务端和客户端的消息通讯,本篇随笔主要基于SignalR的构建一个基于Winform的服务端和客户端的通讯处理案例,介绍其中的处理过程. 1.SignalR基础知识 SignalR是一个.NET Core/.NET Framework的开源实时框架. SignalR的可使用Web Socket, Server Sent Events 和 Long

手写一个模块化的 TCP 服务端客户端

前面的博客 基于 socket 手写一个 TCP 服务端及客户端 写过一个简单的 TCP 服务端客户端,没有对代码结构进行任何设计,仅仅是实现了相关功能,用于加深对 socket 编程的认识. 这次我们对整个代码结构进行一下优化,使其模块化,易扩展,成为一个简单意义上的“框架”. 对于 Socket 编程这类所需知识偏底层的情况(OS 协议栈的运作机制,TCP 协议的理解,多线程的理解,BIO/NIO 的理解,阻塞函数的运作原理甚至是更底层处理器的中断.网卡等外设与内核的交互.核心态与内核态的切

一个很实用的前端框架Zui

杰哥给我推荐了一个很有用的前端框架-Zui,我看着觉得很神奇的,因为有很多我都不懂.在这里分享总结一下.首先,这是一个中国自己开发的框架,比起很多外国的框架来说,有很详细的API,而且是全中文的,不需要再经过其他人的翻译了.然后,它的内容十分丰富,很系统的分为了:基础,控件,组件,JS插件,视图几大块:而且使用起来,只需要导入js,在适当的地方加上正确的class类就可以了.对于,没有什么js基础的人,也是十分容易上手的.下面我就大体的介绍一下它的各个模块的功能.基础:基础里面我觉得很有用的主要

Node.js是一个事件驱动I/O服务端JavaScript环境

Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎.目的是为了提供撰写可扩充网络程序,如Web服务.第一个版本由Ryan Dahl于2009年发布,后来,Joyent雇用了Dahl,并协助发展Node.js. 其他编程语言的类似开发环境,包含Twisted于Python,Perl Object Environment于Perl,libevent于C,和EventMachine于Ruby.与一般JavaScript不同的地方,Node.js并不是在Web浏

分享一个很实用的java代码,可以将以逗号分隔的数字以从大到小的方式排序后返回

原文:分享一个很实用的java代码,可以将以逗号分隔的数字以从大到小的方式排序后返回 源代码下载地址:http://www.zuidaima.com/share/1550463693032448.htm 对于web开发中,多个id的排序很实用,有需要的牛人可以下载. package com.zuidaima.math; import java.util.Arrays; /** *@author www.zuidaima.com **/ public class SortIDString { pu