第六章:基于UDP的服务端/客户端
1. UDP为什么比TCP速度快?为什么TCP数据传输可靠而UDP数据传输不可靠?
UDP和TCP不同,不进行流量控制。由于该控制涉及到套接字的连接和结束,以及整个数据收发过程,因此,TCP传输的数据是可以信赖的。相反,UDP不进行这种控制,因此无法信任数据的传输,但正因UDP不进行流量控制,所以比TCP更快。
3. UDP数据包向对方主机的UDP套接字传递过程中,IP和UDP分别负责哪些部分?
IP负责链路选择。UDP负责端到端的传输。
4. UDP一般比TCP快,但根据交换数据的特点,其差异可大可小。请说明何种情况下UDP的性能优于TCP。
UDP与TCP不同,不经过连接以及断开SOCKET的过程,因此,在频繁的连接及断开的情况下,UDP的数据收发能力会凸显出更好的性能。
5. 客户端TCP套接字调用connect函数时自动分配IP和端口号。UDP中不调用bind函数,那何时分配IP和端口号?
首次调用sendto函数时,发现尚未分配信息,则给相应的套接字自动分配IP和端口号。
6. TCP客户端必须调用connect函数,而UDP中可以选择性调用。请问,在UDP中调用connect函数有哪些好处?
每当以UDP套接字为对像调用sendto函数时,都要经过以下过程
- 第一阶段:为目标UDP注册端口和IP
- 第二阶段:数据传输
- 第三阶段:删除UDP注册的IP和端口信息
其中,只要调用connect函数,就可以忽略每次传输数据时反复进行的第一阶段和第三阶段。然而,调用connect函数并不意味着经过连接过程,只是将IP地址和端口号指定在UDP的发送对象上。这样connect函数使用后,还可以用write、read函数进行数据处理,而不必使用sendto、recvfrom。
7. 修改代码,uecho客户端/服务端轮流收发消息。 server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char* message);
int main(int argc, char* argv[]){
int serv_sock, clnt_sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_adr, clnt_adr;
socklen_t clnt_adr_sz;
if (argc != 2) {
printf("Usgae : %s <port>\n", argv[0]);
exit(1);
}
serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if(serv_sock==-1){
error_handling("socket() error");
}
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET;
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_adr.sin_port = htons(atoi(argv[1]));
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1){
error_handling("bind() error");
}
clnt_adr_sz = sizeof(clnt_adr);
while(1){
str_len = recvfrom(serv_sock, message, BUF_SIZE, 0, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
message[str_len]=0;
printf("Message from client :%s ", message);
fputs("Insert message (q to quit):", stdout);
fgets(message, BUF_SIZE, stdin);
if(!strcmp(message, "q\n")||!strcmp(message, "q\n")){
break;
}
sendto(serv_sock, message, strlen(message), 0, (struct sockaddr*)&clnt_adr, clnt_adr_sz);
}
close(serv_sock);
return 0;
}
void error_handling(char* message) {
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
client.c
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#define BUF_SIZE 30
void error_handling(char* message);
int main(int argc, char* argv[]){
int sock;
char message[BUF_SIZE];
int str_len;
struct sockaddr_in serv_addr, from_addr;
socklen_t adr_sz;
if(argc!=3){
printf("Usage : %s <IP><port>\n", argv[0]);
exit(1);
}
sock = socket(PF_INET, SOCK_DGRAM, 0);
if(sock==-1){
error_handling("socket() error");
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
serv_addr.sin_port = htons(atoi(argv[2]));
while(1){
fputs("Input message(Q to quit): ", stdout);
fgets(message, BUF_SIZE, stdin);
if(!strcmp(message, "q\n")||!strcmp(message, "q\n")){
break;
}
sendto(sock, message, strlen(message), 0, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
adr_sz = sizeof(from_addr);
str_len = recvfrom(sock, message, BUF_SIZE, 0, (struct sockaddr*)&from_addr, &adr_sz);
message[str_len] = 0;
printf("Message from server: %s", message);
}
close(sock);
return 0;
}
void error_handling(char*message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}