转:http://www.linuxforu.com/2011/11/socket-api-part-4-datagrams/

By Pankaj Tanwar on November 1, 2011 in CodingDevelopers · 0 Comments

Let’s try to develop server clients using UDP, the protocol behind some important services like DNS, NFS, etc.

UDP, the User Datagram Protocol, is a connectionless protocol. This means you don’t establish a connection before sending data (like the three-way handshake for TCP); you just send the data in the form of a datagram, to the target address. That’s why we also call it a unreliable protocol, as we do not know or care if the datagram reached the recipient or not.

The code

Now, as we usually do, let’s jump to the program. The code in this article is a modified version of the echo server/clients programs in the UNIX Network Programming by Stevens et al. This file isudpserver.c:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/in.h>
 
int main()
{
    int sfd, n;
    socklen_t len;
    char line[128];
    struct sockaddr_in saddr, caddr;
 
    sfd = socket(AF_INET, SOCK_DGRAM, 0);  
 
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    saddr.sin_addr.s_addr = htonl(INADDR_ANY);
    saddr.sin_port = htons(2910);
 
    bind(sfd, (struct sockaddr *)&saddr, sizeof(saddr));
 
    printf("Server running\n");
    for(;;) {
        len=sizeof(caddr);
        n=recvfrom(sfd, line, 128, 0, (struct sockaddr *)&caddr, &len);
        sendto(sfd, line, n, 0, (struct sockaddr *)&caddr, len);
    }
 
    return 0;
}

This is almost like the previous code; let, let’s discuss the differences. First, the call to socket(): the SOCK_STREAM that was for TCP/SCTP is replaced with SOCK_DGRAM. Then we did a bind() to the address and port, and the server was ready to receive data from the client (which, in this case, is simple text that fits in a single packet).

Next, you see there is no listen() call. Instead you are waiting to receive data at recvform() and when received, echo it back to the client using sendto().

Before looking into these functions, observe that your server does not fork() to serve each request, but iteratively serves requests at each iteration in the infinite loop. That’s because in TCP, you have to maintain a connection with each client, and so need a separate thread, but in UDP you just reply to a single client at a time, and it’s free to receive data from the next client in the next iteration.

Thus, you see that we need a buffer for the server that will hold data from clients in queue, to serve in a first-in-first-out order. Most TCP servers are concurrent, and UDP servers are iterative.

Sending and receiving

Let’s cover the new functions used for datagrams; first is recvfrom():

#include <sys/socket.h>
ssize_t recvfrom (int sockfd, void *buf, size_t nbytes,
    int flags, struct sockaddr *from, socklen_t *addrlen);

This function blocks the server until it receives some data at sockfd from the address specified in the *from argument, and writes nbytes to *buf. The flag argument is formed by OR-ing one or more values, but we’re not using it, so it is 0. The last argument, *addrlen, is a pointer to the size of the socket address structure.

Now, send data using sendto():

#include <sys/socket.h>
ssize_t sendto (int sockfd, const void *buf, size_t nbytes,
    int flags, const struct sockaddr *to, socklen_t addrlen);

This function sends the *buf data of size nbytes through sockfd to the address stored in the *tostructure. Its size is addrlen, and do note that it is not a reference, as it was in recvfrom(). The flags argument is as in recvfrom(). Both functions return the number of bytes read/written.

And the code for the client, udpclient.c, is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 
#include <sys/socket.h>
 
ssize_t recvfrom (int sockfd, void *buff, size_t nbytes,
    int flags, struct sockaddr *from, socklen_t *addrlen);
 
ssize_t sendto (int sockfd, const void *buff, size_t nbytes,
    int flags, const struct sockaddr *to, socklen_t addrlen);
 
**/
 
 
#include <stdio.h>
#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#define MAX 100
 
int main(int argc, char** argv)
{
    int sfd, n;
    socklen_t len;
    char sline[MAX], rline[MAX+1];
    struct sockaddr_in saddr;
 
    if(argc!=2) {
        printf("Usage: %s ipaddress\n", argv[0]);
        return -1;
    }
 
    sfd = socket(AF_INET, SOCK_DGRAM, 0);  
 
    bzero(&saddr, sizeof(saddr));
    saddr.sin_family = AF_INET;
    inet_pton(AF_INET, argv[1], &saddr.sin_addr);
    saddr.sin_port = htons(2910);
 
    printf("Client Running\n");
    while(fgets(sline, MAX, stdin)!=NULL) {
        len=sizeof(saddr);
        sendto(sfd, sline, strlen(sline), 0, (struct sockaddr *)&saddr, len);
        n=recvfrom(sfd, rline, MAX, 0, NULL, NULL);
        rline[n]=0;
        fputs(rline, stdout);
    }
 
    return 0;
}

The client program is very simple -– it just sends the line read from the standard input to the server using sendto(), and reads the reply from the server using recvfrom().

Here, don’t specify the address and port you are receiving from, so any random client/server can send data to you if it knows the port number assigned to your client. If you are interested in replies from a specific server, you can store the structure returned by the recvfrom() and compare it with the structure used in sendto().

This may be a problem if your server is multi-homed (with multiple IPs), and the server has not bound the address like we usually do, using INADDR_ANY.

Figure 1: Starting server

Figure 2: Client running

Before ending, let’s look into some problems with UDP.

First, there is no way to know if your datagram has reached the other side. You cannot know whether the request or the reply is lost. This is okay for a server, but your client may keep on waiting for a reply. In that case, you can specify a time-out in the call to recvfrom, so it doesn’t wait forever.

And here, I end the article, signing out with my usual, “FOSS ROCKS!”

The Socket API, Part 4: Datagrams的更多相关文章

  1. Creating Your Own Server: The Socket API, Part 1

    转:http://www.linuxforu.com/2011/08/creating-your-own-server-the-socket-api-part-1/ By Pankaj Tanwar  ...

  2. Creating Your Own Server: The Socket API, Part 2

    转:http://www.linuxforu.com/2011/09/creating-your-own-server-the-socket-api-part-2/ By Pankaj Tanwar  ...

  3. UNIX网络编程——SOCKET API和TCP STATE的对应关系_三次握手_四次挥手及TCP延迟确认

    在socket系统调用中,如何完成三次握手和四次挥手: SOCK_DGRAM即UDP中的connect操作知识在内核中注册对方机器的IP和PORT信息,并没有建立连接的过程,即没有发包,close也不 ...

  4. c/c++ socket API 调用后的错误判断 perror errno

    socket API 调用后的错误判断 perror errno 调用完socket API后,需要判断调用是否成功与失败.如果失败,会自动设置errno(是个整数), 并且用perror可以打印出具 ...

  5. JNI 和 socket api

    1.JavaVM 和 JNIEnvJNIEnv是一个与线程相关的变量,不同线程的JNIEnv彼此独立.JavaVM是虚拟机在JNI层的代表,在一个虚拟机进程中只有一个JavaVM,因此该进程的所有线程 ...

  6. LwIP - raw/callback API、协议栈API(sequential API)、BSD API(或者说 SOCKET API)

    1.使用raw/callback API编程,用户编程的方法是向内核注册各种自定义的回调函数,回调函数是与内核实现交换的唯一方式. recv_udp, accept_function, sent_tc ...

  7. socket编程 ------ BSD socket API

    伯克利套接字(Berkeley sockets),也称为BSD Socket.伯克利套接字的应用编程接口(API)是采用C语言的进程间通信的库,经常用在计算机网络间的通信. BSD Socket的应用 ...

  8. Python Socket API 笔记

    将上节中的C#该成Python版的容易程度大大超出了我的意料之外.从来没有发现,仅仅用灰尘简单的几句话就实现了该程序的主要功能,可见python的简易和强大之处.这里先对SocketAPI 做一下总结 ...

  9. TCP协议和socket API 学习笔记

    本文转载至 http://blog.chinaunix.net/uid-16979052-id-3350958.html 分类:  原文地址:TCP协议和socket API 学习笔记 作者:gilb ...

随机推荐

  1. 成为IBM精英讲师-一分耕耘 一份收获 同时也多了一份责任!

    成为IBM精英讲师 一分耕耘 一份收获 同时也多了一份责任! http://www.webspherechina.net/?action-iste-type-lecturerlist 650) thi ...

  2. linux中ctrl+z和ctrl+c的区别

    ctrl+c和ctrl+z都是中断命令,但是他们的作用却不一样.ctrl+c是强制中断程序的执行,而ctrl+z的是将任务中断,但是此任务并没有结束,他仍然在进程中他只是维持挂起的状态,用户可以使用f ...

  3. Apache Spark的部署环境的小记

    Spark的单机版便于测试,同时通过SSH用Spark的内置部署脚本搭建Spark集群,使用Mesos.Yarn或者Chef来部署Spark.对于Spark在云环境中的部署,比如在EC2(基本环境和E ...

  4. 安装完 MySQL 后必须调整的 10 项配置(转)

    英文原文:10 MySQL settings to tune after installation 译文原文:安装完 MySQL 后必须调整的 10 项配置 当我们被人雇来监测MySQL性能时,人们希 ...

  5. 使用IIS6.0遇到问题后,常用的几种解决方法

    1.检查 .Net Framework,是否安装完全,不确定的情况下使用:aspnet_regiis.exe -i 或者 aspnet_regiis.exe -r 2.检查 IIS 6.0 其它相关配 ...

  6. usb库文件usb_desc.c分析

    参考<圈圈教你玩USB> usb协议中使用的是小端结构,所以实际数据在传输时是低字节在先的. 设备描述符的实现: 已知每个设备都必须有且仅有一个设备描述符,它的结构在USB协议中有详细的定 ...

  7. POJ 3616 Milking Time (排序+dp)

    题目链接:http://poj.org/problem?id=3616 有头牛产奶n小时(n<=1000000),但必须在m个时间段内取奶,给定每个时间段的起始时间和结束时间以及取奶质量 且两次 ...

  8. POJ1384Piggy-Bank(DP)

    POJ1384http://poj.org/problem?id=1384 最简单的完全背包问题,注意下初始化为INF就可以. #include <map> #include <se ...

  9. 8.3 LIS LCS LCIS(完结了==!)

    感觉这个专题真不好捉,伤心了,慢慢啃吧,孩纸 地址http://acm.hust.edu.cn/vjudge/contest/view.action?cid=28195#overview 密码  ac ...

  10. 利用HTML5开发Android(2)---Android中构建HTML5应用

    使用WebView控件 与其他控件的使用方法相同 在layout中使用一个<WebView>标签 WebView不包括导航栏,地址栏等完整浏览器功能,只用于显示一个网页 在WebView中 ...