Tải bản đầy đủ (.pdf) (28 trang)

Bài giảng Lập trình mạng: Lập trình UDP socket nâng cao - TS. Nguyễn Hoài Sơn

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (733.19 KB, 28 trang )

Lập trình UDP socket nâng cao

TS. Nguyễn Hồi Sơn
Bộ mơn mạng và Truyền thơng máy tính,
Đại học Cơng nghệ, Đại học QG Hà Nội


UDP hay TCP ?





Gửi tin broadcast hay multicast phải dùng UDP
Có thể dùng UDP với các ứng dụng với yêu cầu trả lời đơn giản
Có thể dùng UDP vỚI các ứng dụng LAN




Nên dùng UDP với truyền tin đa phương tiện




Băng thơng lớn, ít lỗi
Điều khiển luồng?

Dùng TCP với việc truyền dữ liệu lớn



TFTP (Trivial File Transfer Protocol) là một ngoại lệ


Vấn đề với UDP


Làm thế nào để lấy địa chỉ IP đích?






Địa chỉ IP đích có thể là địa chỉ unicast hoặc địa
chi multicast

Làm thế nào biết và xử lý trong trường hợp
gói tin UDP lớn hơn kích thước buffer?
Làm thế nào để đảm bảo tính tin cậy khi
đường truyền có lỗi


Acknowledgement, timeout, gửi lại


Lấy cờ hiệu, địa chỉ IP đích và số hiệu
giao diện mạng


Dùng sendmsg và recvmsg để lấy




cờ hiệu từ socket
các dữ liệu phụ thuộc như địa chỉ IP và số hiệu
giao diện đích trong trường hợp có nhiều giao
diện mạng


Remind: sendmsg and recvmsg
#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);
Both return: number of bytes read or written if OK, –1 on error
struct msghdr {
void *msg_name;
/* protocol address */
socklen_t msg_namelen; /* size of protocol address */
struct iovec *msg_iov;
/* scatter/gather array */
int msg_iovlen;
/* # elements in msg_iov */
void *msg_control;
/* ancillary data (cmsghdr struct) */
socklen_t msg_controllen; /* length of ancillary data */
int msg_flags;
/* flags returned by recvmsg() */
};



Remind: sendmsg and recvmsg (2)


thiết lập cờ chức năng cho việc xuất nhập dữ liệu









MSG_DONTROUTE: bỏ qua truy vấn bảng định tuyến
MSG_DONTWAIT: không chờ khi xuất nhập dữ liệu
MSG_OOB: gửi và nhận dữ liệu ngoài luồng (out-of-band)
MSG_PEEK: kiểm tra dữ liệu vào nhưng vẫn giữ nguyên
dữ liệu trong buffer
MSG_WAITALL: đợi tất cả dữ liệu yêu cầu

Cờ chức năng trả về bởi hàm recvmsg




MSG_BCAST
MSG_MCAST
MSG_TRUNC



Remind: Sau khi hàm recvmsg trả kết quả
về


Ví dụ: hàm recvfrom_flags


ssize_t recvfromflags(int fd, void *ptr, size_t nbytes, int
*flagsp, SA *sa, socklen_t *salenptr, struct
unp_in_pktinfo *pktp)


struct unp_in_pktinfo
{
struct in_addr ipi_addr; /* destination IPv4 address */
int ipi_ifindex; /* received interface index */
};



Trả về:





Giá trị của msg_flags được trả về bởi hàm recvmsg
Địa chỉ đích của gói tin nhận được (sử dụng tùy biến socket
IP_RECVDSTADDR)
Số hiệu của giao diện nhận gói tin (sử dụng tùy biến socket

IP_RECVIF)


Dữ liệu phụ thuộc




Gửi và nhận bằng thành phần msg_control và msg_controllen của
cấu trúc msghdr với hàm sendmsg và recvmsg
chứa một hoặc nhiều đối tượng dữ liệu phụ thuộc



each one begins with a cmsghdr structure
struct cmsghdr {
socklen_t cmsg_len; /* length in bytes, including this structure */
int cmsg_level; /* protocol family */
int cmsg_type; /* protocol-specific type */
/* followed by unsigned char cmsg_data[] */
};


Dữ liệu phụ thuộc chứa hai đối tượng dữ
liệu


Các hàm macros để đơn giản hóa xử lý
dữ liệu phụ thuộc
#include <sys/socket.h>

#include <sys/param.h>
/* for ALIGN macro on many implementations */
struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr) ;
Returns: pointer to first cmsghdr structure or NULL if no ancillary data
struct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr) ;
Returns: pointer to next cmsghdr structure or NULL if no more ancillary data objects
unsigned char *CMSG_DATA(struct cmsghdr *cmsgptr) ;
Returns: pointer to first byte of data associated with cmsghdr structure
unsigned int CMSG_LEN(unsigned int length) ;
Returns: value to store in cmsg_len given the amount of data
unsigned int CMSG_SPACE(unsigned int length) ;
Returns: total size of an ancillary data object given the amount of data


recvfrom_flags function (2)


advio/recvfromflags.c
Dữ liệu phụ thuộc kiểu IP_RECVIF


Hàm dg_echo với recvfrom_flags


advio/dgechoaddr.c


Chia nhỏ gói tin UDP
Khi nhận một gói tin UDP lớn hơn kích thước buffer,
hệ thống có thể xử lý theo các cách sau tùy thuộc vào

từng OS
 Bỏ phần dữ liệu vượt quá kích thước buffer, và trả về
cờ MSG_TRUNC cho tiến trình xử lý
 recvmsg thiết lập cờ MSG_TRUNC trong msg_flags
của cấu trúc msghdr
 Bỏ phần dữ liệu thừa và khơng thơng báo cho tiến
trình xử lý
 Giữ phần dữ liệu thừa và trả về ở lần đọc dữ liệu
socket sau đó
=> cần thiết lập kích thước buffer lớn hơn kích thước lớn
nhất của gói tin UDP có thể nhận được một byte




Tạo tính tin cậy cho ứng dụng UDPs


Thực hiện 2 yêu cầu


Số thứ tự (Sequence numbers): Bên nhận xác nhận số

thứ tự của thông báo nhận được




Client thêm số thứ tự vào mỗi thông báo yêu cầu và máy chủ
gửi lại số thứ tự này trong thông báo trả lời


Timeout và gửi lại: khơi phục các gói tin bị mất mát



Gửi thông báo yêu cầu và đợi trong N giây
Nếu khơng có thơng báo trả lời, gửi lại và đợi thêm N giây


Lặp lại nhiều lần


Tạo tính tin cậy cho ứng dụng UDPs (2)


Làm thế nào để xác định N thích hợp?
RTT trong mạng LAN và WAN là khác nhau
 RTT giữa máy khách và máy chủ có thể thay đổi
nhanh chóng
 Cần tính tốn RTT thực sự
=> Giải pháp từ [Jacobson 1988]


g = 1/8, h = 1/4


Vấn đề không rõ ràng khi gửi lại

Thông báo yêu cầu bị mất?
Thông báo trả lời bị mất?

Khoảng RTO là quá nhỏ?

RTT là bao nhiêu?


Giải pháp




Thêm nhãn thời gian vào mỗi thông báo và
máy chủ cũng phải gửi lại nhãn thời gian này
Tính tốn RTT bằng thời gian nhận gói tin trừ
đi nhãn thời gian ghi trong gói tin

=> Hàm dg_send_recv


struct rtt_info


struct rtt_info {
float rtt_rtt;
/* RTT gần nhất, đơn vị giây */
float rtt_srtt;
/* Ước lượng RTT, đơn vị giây */
float rtt_rttvar;
/* Ước lượng độ lệch trung bình, đơn vị
giây */
float rtt_rto;

/* RTT hiện tại, đơn vị giây */
int rtt_nrexmt;
/* số lần gửi lại: 0, 1, 2, ... */
uint32_t rtt_base;
/* thời gian (giây) tính từ 1/1/1970 */
};


dg_send_recv function


rtt/dg_send_recv.c

g = 1/8, h = 1/4


Các bước thực hiện
Khởi tạo đồng hồ đếm độ trễ

rtt_init(&rtti
nfo)

Khởi tạo dữ liệu gửi msgsend
• Tiêu đề chứa sequence number và nhãn thời gian
Đặt tín hiệu chng
• Thời gian đổ chng ban đầu
= độ trễ ước lượng

alarm(rtt_star
t(&rttinfo))


timeout
Chờ và nhận gói tin trả lời

Tính tốn lại độ trễ ước lượng

rtt_stop(&rttinfo,
rtt_ts(&rttinfo) recvhdr.ts)


Các hàm tính tốn độ trễ
lib/rtt.c
 rtt_init
 rtt_ts, rtt_newpack, rtt_start, rtt_stop


Xuất nhập dữ liệu I/O bằng
điều khiển tín hiệu


Mơ hình xuất nhập dữ liệu bằng điều
khiển tín hiệu
kernel

application
establish
SIGIO signal
handler
process
continues

executing

signal
handler
recvfrom

process blocks
while data is
copied into
application
buffer

sigaction system call
return
wait
for
data

deliver SIGIO
datagram ready
system call

copy datagram

return OK
process
datagram

copy complete


copy
data
from
kernel
to user


Các bước thực hiện xuất nhập dữ liệu
bằng điều khiển tín hiệu



Thiết lập hàm xử lý tín hiệu SIGIO
Thiết lập chủ sở hữu socket




sử dụng lệnh F_SETOWN của hàm fcntl

Cho phép xuất nhập dữ liệu bằng điều khiển
tín hiệu


sử dụng lệnh F_SETFL của hàm fcntl để thiết lập
cờ O_ASYNC


×