1. 程式人生 > >linux網路程式設計之用socket實現簡單客戶端和服務端的通訊(基於UDP)

linux網路程式設計之用socket實現簡單客戶端和服務端的通訊(基於UDP)

1、sendto和recvfrom函式介紹

sendto(經socket傳送資料)

相關函式 send , sendmsg,recv , recvfrom , socket
表頭檔案 #include < sys/types.h >
#include < sys/socket.h >
定義函式 int sendto ( int s , const void * msg, int len, unsigned int flags, const
struct sockaddr * to , int tolen ) ;
函式說明 sendto() 用來將資料由指定的socket傳給對方主機。引數s為已建好連線的socket,如果利用UDP協議則不需經過連線操作。引數msg指向欲連線的資料內容,引數flags 一般設0,詳細描述請參考send()。引數to用來指定欲傳送的網路地址,結構sockaddr請參考bind()。引數tolen為sockaddr的結果長度。
返回值 成功則返回實際傳送出去的字元數,失敗返回-1,錯誤原因存於errno 中。
錯誤程式碼 EBADF 引數s非法的socket處理程式碼。
EFAULT 引數中有一指標指向無法存取的記憶體空間。
WNOTSOCK canshu s為一檔案描述詞,非socket。
EINTR 被訊號所中斷。
EAGAIN 此動作會令程序阻斷,但引數s的soket為補課阻斷的。
ENOBUFS 系統的緩衝記憶體不足。
EINVAL 傳給系統呼叫的引數不正確。
recvfrom(經socket接收資料)
相關函式 recv,recvmsg,send,sendto,socket
表頭檔案 #include<sys/types.h>

#include<sys/socket.h>
定義函式 int recvfrom(int s,void *buf,int len,unsigned int flags ,struct sockaddr *from ,int *fromlen);
函式說明 recv()用來接收遠端主機經指定的socket 傳來的資料,並把資料存到由引數buf 指向的記憶體空間,引數len 為可接收資料的最大長度。引數flags 一般設0,其他數值定義請參考recv()。引數from用來指定欲傳送的網路地址,結構sockaddr 請參考bind()。引數fromlen為sockaddr的結構長度。
返回值 成功則返回接收到的字元數,失敗則返回-1,錯誤原因存於errno中。
錯誤程式碼 EBADF 引數s非合法的socket處理程式碼
EFAULT 引數中有一指標指向無法存取的記憶體空間。
ENOTSOCK 引數s為一檔案描述詞,非socket。
EINTR 被訊號所中斷。
EAGAIN 此動作會令程序阻斷,但引數s的socket為不可阻斷。
ENOBUFS 系統的緩衝記憶體不足
ENOMEM 核心記憶體不足
EINVAL 傳給系統呼叫的引數不正確。

2、單客戶端和服務端的通訊(基於UDP)   圖解

3、單客戶端和服務端的通訊(基於UDP)   程式碼

1、服務端程式碼socket3.c

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

#define PORT 8888
#define MAX_MSG_SIZE 1024

int main(void)
{
   int sockfd, addrlen, n;
   struct sockaddr_in addr;
   char msg[MAX_MSG_SIZE];
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sockfd < 0)
   {
      fprintf(stderr, "socket failed\n");
      exit(EXIT_FAILURE);
   }
   addrlen = sizeof(struct sockaddr_in);
   bzero(&addr, addrlen);
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
   addr.sin_port = htons(PORT);
   if (bind(sockfd, (struct sockaddr*)(&addr), addrlen) < 0)
   {
      fprintf(stderr, "bind fail\n");
      exit(EXIT_FAILURE);
   }
   puts("bind success");
   while (1)
   {
      bzero(msg, MAX_MSG_SIZE);
      n = recvfrom(sockfd, msg, sizeof(msg), 0, (struct sockaddr *)(&addr), &addrlen);
      fprintf(stdout, "Recevie message from client is %s\n", msg);
      fgets(msg, MAX_MSG_SIZE,stdin);
      printf("Server endpoint input message %s\n", msg);
      sendto(sockfd, msg, n, 0,(struct sockaddr *)(&addr), addrlen);
   }
   close(sockfd);
   exit(EXIT_SUCCESS);
}

2、客戶端程式碼socket4.c


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

#define MAX_BUF_SIZE 1024
#define PORT 8888

int main() 
{
   int sockfd, addrlen, n;
   char buffer[MAX_BUF_SIZE];
   struct sockaddr_in addr;
   sockfd = socket(AF_INET, SOCK_DGRAM, 0);
   if (sockfd < 0)
   {
      fprintf(stderr, "socket falied\n");
      exit(EXIT_FAILURE);
   }
   addrlen = sizeof(struct sockaddr_in);
   bzero(&addr, addrlen);
   addr.sin_family = AF_INET;
   addr.sin_port = htons(PORT);
   addr.sin_addr.s_addr = htonl(INADDR_ANY);
     
   puts("socket success");
   while(1)
   {
       bzero(buffer, MAX_BUF_SIZE);
       fgets(buffer, MAX_BUF_SIZE, stdin);
       sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)(&addr), addrlen);
       printf("client send msg is %s\n", buffer);
       n = recvfrom(sockfd, buffer, strlen(buffer), 0, (struct sockaddr *)(&addr), &addrlen);
       fprintf(stdout, "clinet Receive message from server is %s\n", buffer);
   }
   close(sockfd);
   exit(0);
   return 0;
}

4、執行結果


5、總結

服務端:socket->bind->(sendto 、revcfrom)

客戶端:socket->(sendto 、revcfrom)

upd不是面相連線的,這個是和tcp本質區別,資料可能會亂序,重複。