linux下udp 網絡間通訊程序+書上沒有提過的問題本身想法

        通過五一好幾天的娛樂,這幾天翻過頭又把socket的UDP編程反芻一下,借了幾本書又思考了一下,又把給我解答問題的朋友們的留言看了一遍,對UDP的socket編程終於有所小獲,在網絡中跨平臺試了一下,好使,甚是開心,並打算在此總結一下以供初入門的朋友們少走彎路,並在此感謝積極給我解答問題的朋友們 @聖何塞白話人  @mallon   @zino @xinzaibing @mallon  @dd   是大家讓我懂得了開源的精神,我也會以開源支持者的身份積極參與其中。下面是個人正文。編程

        Linux下的socket編程主要就是幾個結構體和幾個函數就能夠實現用協議通訊的功能。主要的結構體以下:服務器

struct in_addr
{
    in_addr_t s_addr; //in_addr_t 其實就是unsigned long
};

struct sockaddr
{
    unsigned short sa_family;
    char sa_data[14];
};

struct sockaddr_in
{
    short int sin_family;
    unsigned short int sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
};

        第二個結構體和第三個結構體其實內容是同樣的,只是後面講的要用到的socket的函數bind, recvfrom, sendto, listen, accept, recv, send 等函數中用到的參數都是struct sockaddr,可是賦值的時候仍是用sockaddr_in方便,因而就略顯「畫蛇添足」的給struct sockaddr_in定義的結構體的成員變量賦值,在調用函數的時候再用(struct sockaddr*)強制轉換一下(這些在書上都是不說的)。

        主要須要調用的函數上面提到了一些,這裏就不說了,用終端中的man能夠查到很詳細的東西。下面貼一下程序:網絡

服務器程序:socket

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

#define MAXLINE 80
#define sport 4567
#define sip "49.140.191.30"


void do_echo(int sockfd, struct sockaddr *pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
int i=0;
while(1)
{
printf("OK %d\n",i);
i++;
len = clilen;
/* waiting for receive data */
n = recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
/* sent data back to client */
sendto(sockfd, mesg, n, 0, pcliaddr, len);

}
}


/*主函數*/
int main(void)
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = socket(AF_INET, SOCK_DGRAM, 0); /* create a socket */

/* init servaddr */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr=inet_addr(sip);
//servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(sport);

/* bind address and port to socket */
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind error");
exit(1);
}

do_echo(sockfd, (struct sockaddr *)&cliaddr, sizeof(cliaddr));

return 0;
}

客戶端程序:

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

#define MAXLINE 80
#define SERV_PORT 4567

void do_cli(FILE *fp, int sockfd, struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];

/* connect to server */
if(connect(sockfd, (struct sockaddr *)pservaddr, servlen) == -1)
{
perror("connect error");
exit(1);
}

while(fgets(sendline, MAXLINE, fp) != NULL)
{
/* read a line and send to server */
write(sockfd, sendline, strlen(sendline));
/* receive data from server */
n = read(sockfd, recvline, MAXLINE);
if(n == -1)
{
perror("read error");
exit(1);
}
recvline[n] = 0; /* terminate string */
fputs(recvline, stdout);
}
}

int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;

/* check args */
if(argc != 2)
{
printf("usage: udpclient <IPaddress>\n");
exit(1);
}

/* init servaddr */
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if(inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
{
printf("[%s] is not a valid IPaddress\n", argv[1]);
exit(1);
}

sockfd = socket(AF_INET, SOCK_DGRAM, 0);

do_cli(stdin, sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

return 0;
}

        在實際狀況下,服務器用的是公網IP地址,而我在學校用的校園網正好也是給每一個學生分配公網IP地址(封殺路由器),因此正好就把本機的公網IP做爲服務器的IP地址,端口隨意設了一個沒有用的。客戶端的程序和書上不一樣之處(優勢)在於:當客戶端鏈接到主機以後(connect調用以後),檢測一下是否讀到服務器回覆的消息,若是沒有回覆就顯示錯誤並退出,防止接收不到消息一直等待。

        在本機中測試良好;在網絡環境中,我在本機中開啓服務器端程序,同窗在win下用udp小工具做爲客戶端,一樣能夠達到互聯的功能。同窗用的是CMCC,是私有IP地址。(但這都不是問題的關鍵,由於NAT的做用把私有IP地址和端口號都轉變爲公有的IP地址和另外一個端口號)函數

        在這篇文章中要重點說書上沒有的東西:(按個人我的理解,因爲還在不斷學習中,共同進步爲原則,寫出來在批判的過程當中一塊兒發現本質)工具

1,socket究竟是什麼?學習

int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);

sockfd是int類型,但其實它是具備指針功能的(雖然它不是指針),可是在建立socket的同時已經開闢了一段存儲空間,用於存放和此socket綁定的相關信息。雖然在表面上不是指針,可是經過socket號能夠肯定是哪段存儲空間這樣便肯定是哪段信息,和指針功能同樣。

2,在服務器程序中,在37行測試

struct sockaddr_in servaddr, cliaddr;

對servaddr和cliaddr作了定義,可是後面只對servaddr賦值,cliaddr中只是定義時系統賦的初始值,用gdb顯示以下:spa

(gdb) print cliaddr
$5 = {sin_family = 45860, sin_port = 42, sin_addr = {s_addr = 2797556}, 
  sin_zero = "U<\026\000Y\207\004\b"}

可是,服務器獲得了客戶端發送的信息而且回覆了客戶端。它到底是如何獲得客戶端的IP地址和端口號的呢?因爲UDP是在傳輸層,不少下層一些的東西都不知道,要想弄明白這個我還須要繼續學習(這也是我要作的),可是如今入門姑且這樣理解,在這個日子mark一下,等發下一篇文章的時候就知道更本質的東西了,也知道我這些天到底有沒有用功啦~~

        姑且就這兩個問題是書上沒有解釋的,如今的書都是一大抄,借來一堆書發現內容都同樣,甚至程序都同樣;還有的書程序很亂,編譯都出錯,書名就不提了,《21天。。。》。。。好了,期待本身的下一篇文章,也是下一個階段(雖然我如今還很菜~~)。.net

相關文章
相關標籤/搜索