linux網路程式設計之用socket實現簡單客戶端和服務端的通訊(基於UDP)
阿新 • • 發佈:2019-01-02
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本質區別,資料可能會亂序,重複。