2008年8月12日 星期二

UDP Server/Client 範例程式

好像不少人會找這個Sample Code, 小修改一下好了. 先前的Code有不少的Warning出現而且會Crash耶!
底下分別列出UDP Server及Client的範例程式.

UDP Server(udp-server.c) 利用 socket 介面設計網路應用程式程式啟動後等待 client 端連線,連線後印出對方之 IP 位址並顯示對方所傳遞之訊息,並回送給 Client 端。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h>
#include <string.h>
#include <arpa/inet.h>

#define SERV_PORT 5134

#define MAXNAME 1024

extern int errno;

main(){
        int socket_fd;   /* file description into transport */
        int recfd; /* file descriptor to accept        */
        int length; /* length of address structure      */
        int nbytes; /* the number of read **/
        char buf[BUFSIZ];
        struct sockaddr_in myaddr; /* address of this service */
        struct sockaddr_in client_addr; /* address of client    */
        /*
         *      Get a socket into UDP/IP
         */
        if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) <0) {
                perror ("socket failed");
                exit(EXIT_FAILURE);
        }
        /*
         *    Set up our address
         */
        bzero ((char *)&myaddr, sizeof(myaddr));
        myaddr.sin_family = AF_INET;
        myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        myaddr.sin_port = htons(SERV_PORT);

        /*
         *     Bind to the address to which the service will be offered
         */
        if (bind(socket_fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) <0) {
                perror ("bind failed\n");
                exit(1);
        }

        /*
         * Loop continuously, waiting for datagrams
         * and response a message
         */
        length = sizeof(client_addr);
        printf("Server is ready to receive !!\n");
        printf("Can strike Cntrl-c to stop Server >>\n");
        while (1) {
                if ((nbytes = recvfrom(socket_fd, &buf, MAXNAME, 0, (struct sockaddr*)&client_addr, (socklen_t *)&length)) <0) {
                        perror ("could not read datagram!!");
                        continue;
                }


                printf("Received data form %s : %d\n", inet_ntoa(client_addr.sin_addr), htons(client_addr.sin_port));
                printf("%s\n", buf);

                /* return to client */
                if (sendto(socket_fd, &buf, nbytes, 0, (struct sockaddr*)&client_addr, length) < 0) {
                        perror("Could not send datagram!!\n");
                        continue;
                }
                printf("Can Strike Crtl-c to stop Server >>\n");
        }
}
UDP  Client (udp-client.c) 本程式啟動後向 Server (udp server) 要求連線,並送出某檔案給 Server,再由 Server 收回該檔案並顯示出該檔案的內容
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <string.h>

#define SERV_PORT 5134
#define MAXDATA   1024

#define MAXNAME 1024
int main(int argc, char **argv){
        int fd;     /* fd into transport provider */
        int i;     /* loops through user name */
        int length;    /* length of message */
        int size;    /* the length of servaddr */
        int fdesc;    /* file description */
        int ndata;    /* the number of file data */
        char data[MAXDATA]; /* read data form file */
        char data1[MAXDATA];  /*server response a string */
        char buf[BUFSIZ];     /* holds message from server */
        struct hostent *hp;   /* holds IP address of server */
        struct sockaddr_in myaddr;   /* address that client uses */
        struct sockaddr_in servaddr; /* the server's full addr */

        /*
         * Check for proper usage.
         */
        if (argc < 3) {
                fprintf (stderr, "Usage: %s host_name(IP address) file_name\n", argv[0]);
                exit(2);
        }
        /*
         *  Get a socket into UDP
         */
        if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
                perror ("socket failed!");
                exit(1);
        }
        /*
         * Bind to an arbitrary return address.
         */
        bzero((char *)&myaddr, sizeof(myaddr));
        myaddr.sin_family = AF_INET;
        myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        myaddr.sin_port = htons(0);

        if (bind(fd, (struct sockaddr *)&myaddr,
                                sizeof(myaddr)) <0) {
                perror("bind failed!");
                exit(1);
        }
        /*
         * Fill in the server's UDP/IP address
         */

        bzero((char *)&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(SERV_PORT);
        hp = gethostbyname(argv[1]);

        if (hp == 0) {
                fprintf(stderr, "could not obtain address of %s\n", argv[2]);
                return (-1);
        }
        bcopy(hp->h_addr_list[0], (caddr_t)&servaddr.sin_addr,
                        hp->h_length);

        /**開起檔案讀取文字 **/
        fdesc = open(argv[2], O_RDONLY);
        if (fdesc == -1) {
                perror("open file error!");
                exit (1);
        }
        ndata = read (fdesc, data, MAXDATA);
        if (ndata < 0) {
                perror("read file error !");
                exit (1);
        }
        data[ndata + 1] = '\0';

        /* 發送資料給 Server */
        size = sizeof(servaddr);
        if (sendto(fd, data, ndata, 0, (struct sockaddr*)&servaddr, size) == -1) {
                perror("write to server error !");
                exit(1);
        }
        /** 由伺服器接收回應 **/
        if (recvfrom(fd, data1, MAXDATA, 0, (struct sockaddr*)&servaddr, &size) < 0) {
                perror ("read from server error !");
                exit (1);
        }
        /* 印出 server 回應 **/
        printf("%s\n", data1);

}
部份編譯時遇到的Warning問題
Warning 1:
warning: incompatible implicit declaration of built-in function ‘exit’ [enabled by default]
加入#include <stdlib.h>
Warning 2:
warning: incompatible implicit declaration of built-in function ‘bzero’ [enabled by default]
加入#include <string.h>
執行結果如下: udp server side:

udp client side:
資料來源: 底下我原本參考的地方似乎已經失連了.
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/udpserver.c
http://140.127.138.46/tsnien/Teach_Manu/F7858/Aid/udpclient.c

8 則留言:

鄭皓謙 提到...

請問一下UDP的傳輸,為甚麼還要回傳

史丹利 提到...

如果你只是問這個範例程式為什麼要回傳, 就只是很單純的它只是個範例程式.
而實務上就必需要思考一件事情, UDP並不保證資料是一定會到的喔!

鄭皓謙 提到...

史丹利先生,不好意思請問一下,有UDP傳輸但不要回傳的範例麻,就是一直傳......

史丹利 提到...

鄭皓謙:
你要的東西, 只要小改一下就會動了.
(1)把udp-server.c 底下的五行拿掉
/* return to client */
if (sendto(socket_fd, &buf, nbytes, 0, (struct sockaddr*)&client_addr, length) < 0) {
perror("Could not send datagram!!\n");
continue;
}
(2)把udp-client.c底下的7行拿掉
/** 由伺服器接收回應 **/
if (recvfrom(fd, data1, MAXDATA, 0, (struct sockaddr*)&servaddr, &size) < 0) {
perror ("read from server error !");
exit (1);
}
/* 印出 server 回應 **/
printf("%s\n", data1);

XXX 提到...

史丹利先生,不好意思請問一下,假如要使UDP 的SERVER 沒接受到值就不要使CLIENT端傳送值,而做其他事情,要怎麼寫呢?因為SERVER會一直在等數據導至後面事情無法做。

史丹利 提到...

你有兩個方法可以處理,1:改用noonblock,2:用thread去處理。

XXX 提到...


那請問這種有辦法再主程式做判斷式嗎?





CLI_Write(" Waiting for data from UDP client \n\r");
retVal = BsdUdpServer(PORT_NUM);
if(retVal < 0)
CLI_Write(" Failed to read data from the UDP client \n\r");
else{
CLI_Write(" Successfully received data from UDP client \n\r");

unsigned short rec;
rec = uBuf.BsdBuf[0];
switch(rec)
{
case '0':
break;
case '1':
P2OUT |= BIT3;
break;
case '2':
P8OUT |= BIT1;
break;
case '3':
P2OUT &= ~BIT3;
break;
case '4':
P8OUT &= ~BIT1;
break;
default:
CLI_Write("FIALE\n\r");
break;
}

CLI_Write("GPIO CONTROL\n\r");
}

CLI_Write(" Started sending data to UDP server \n\r");




sprintf(state, "%d", P6OUT);// 轉成整數字元串輸出// GPIO狀態

retVal = BsdUdpClient(PORT_NUM);
if(retVal < 0)
CLI_Write(" Failed to send data to UDP sevrer\n\r");
else
CLI_Write(" successfully sent data to UDP server \n\r");

retVal = BsdTcpClient(PORT_NUM);
if(retVal < 0)
CLI_Write(" Failed to establishing connection with TCP server \n\r");
else
CLI_Write(" Connection with TCP server established successfully \n\r");

史丹利 提到...

你這個是CC3100的Code??它是MCU Base, RTOS吧?
這種處理方式不太一樣喔!, 一定有辦法做到你說的, 不過我沒實際碰過你這套code, 應該無法給你明確的建議!