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 4096
int 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 4096
int 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学习笔记,内容来源于极客时间《网络编程实战》。