udpclientNoConnect.c
里邊的內容如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include <errno.h>
#include <syslog.h>
# define MAXLINE 4096int main(int argc, char **argv) {if (argc != 3) {printf("usage: udpclient1 <IPaddress> or <Port>");}int socket_fd;socket_fd = socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET, argv[1], &server_addr.sin_addr);socklen_t server_len = sizeof(server_addr);struct sockaddr *reply_addr;reply_addr = malloc(server_len);char send_line[MAXLINE], recv_line[MAXLINE + 1];socklen_t len;int n;while (fgets(send_line, MAXLINE, stdin) != NULL) {int i = strlen(send_line);if (send_line[i - 1] == '\n') {send_line[i - 1] = 0;}printf("now sending %s\n", send_line);size_t rt = sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &server_addr, server_len);if (rt < 0) {printf("sendto failed");}printf("send bytes: %zu \n", rt);len = 0;recv_line[0] = 0;n = recvfrom(socket_fd, recv_line, MAXLINE, 0, reply_addr, &len);if (n < 0){if (errno){fprintf(stderr, "recvfrom failed: %s (%d)\n", strerror(errno), errno);}else{printf("recvfrom failed");}}recv_line[n] = 0;fputs(recv_line, stdout);fputs("\n", stdout);}exit(0);
}
上邊的代碼沒有connect
函數,gcc udpclienttest.c -o udpclienttest
進行編譯,./udpclienttest 127.0.0.1 8080
執行,然后輸入一些內容,完全沒有反應。
接下來來一段有connect
函數的代碼udpconnectclient.c
如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/socket.h>
#include <errno.h>
#include <syslog.h>
# define MAXLINE 4096int main(int argc, char **argv) {if (argc != 3) {printf("usage: udpclient1 <IPaddress> or <Port>");}int socket_fd;socket_fd = socket(AF_INET, SOCK_DGRAM, 0);struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET, argv[1], &server_addr.sin_addr);socklen_t server_len = sizeof(server_addr);if (connect(socket_fd, (struct sockaddr *) &server_addr, server_len)) {printf("connect failed");}struct sockaddr *reply_addr;reply_addr = malloc(server_len);char send_line[MAXLINE], recv_line[MAXLINE + 1];socklen_t len;int n;while (fgets(send_line, MAXLINE, stdin) != NULL) {int i = strlen(send_line);if (send_line[i - 1] == '\n') {send_line[i - 1] = 0;}printf("now sending %s\n", send_line);size_t rt = sendto(socket_fd, send_line, strlen(send_line), 0, (struct sockaddr *) &server_addr, server_len);if (rt < 0) {printf("sendto failed");}printf("send bytes: %zu \n", rt);len = 0;recv_line[0] = 0;n = recvfrom(socket_fd, recv_line, MAXLINE, 0, reply_addr, &len);if (n < 0){if (errno){fprintf(stderr, "recvfrom failed: %s (%d)\n", strerror(errno), errno);}else{printf("recvfrom failed");}}recv_line[n] = 0;fputs(recv_line, stdout);fputs("\n", stdout);}exit(0);
}
gcc udpconnectclient.c -o udpconnectclient
進行編譯,./udpconnectclient 127.0.0.1 8080
運行,然后嘗試著輸入字符串,發現輸出了連接失敗的原因。
而connect
函數在UDP中的作用就是報出沒有連接的消息,這樣的話,可以讓客戶端知道對端沒有接收方運行。
在對 UDP 進行 connect 之后,關于收發函數的使用,很多書籍是這樣推薦的:
使用 send 或 write 函數來發送,如果使用 sendto 需要把相關的 to 地址信息置零;
使用 recv 或 read 函數來接收,如果使用 recvfrom 需要把對應的 from 地址信息置零。
其實不同的 UNIX 實現對此表現出來的行為不盡相同。在老師的 Linux 4.4.0 環境中,使用 sendto 和 recvfrom,系統會自動忽略 to 和 from 信息。在老師的 macOS 10.13 中,確實需要遵守這樣的規定,使用 sendto 或 recvfrom 會得到一些奇怪的結果,切回 send 和 recv 后正常。
此文章為11月Day 22學習筆記,內容來源于極客時間《網絡編程實戰》。