Tải bản đầy đủ (.docx) (36 trang)

Xây dựng ứng dụng truyền tệp

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 (239.69 KB, 36 trang )

Luận văn tốt nghiệp Nguyễn Nhật Bình
Chơng IV. Xây dựng ứng dụng truyền tệp
I. Giao diện lập trình
I.1. Giao diện lập trình
Bộ giao thức TCP/IP đã định nghĩa đầy đủ các giao thức truyền thông để các máy tính trên mạng có
thể giao tiếp với nhau, che đi cấu trúc vật lý của mạng. Tuy nhiên, để xây dựng các ứng dụng thì sử
dụng TCP/IP là không đủ, bởi vì ngời lập trình sẽ phải tự mình xây dựng những thủ tục giải quyết
từng sự kiện, một giao diện (Application Program Interface) lập trình là cần thiết để cung cấp cho ngời
lập trình một cách tiếp cận đơn giản, dễ hiểu hơn.
UNIX cung cấp cho ngời lập trình hai giao diện chính cho lập trình C:
Sockets lần đầu tiên xuất hiện trong bản BSD UNIX năm 1982 và nhanh chóng phát triển rộng
rãi trong một khoảng thời gian ngắn. Đợc phát triển thêm vào năm 1990 để hỗ trợ giao thức ISO.
Socket đợc gắn với khả năng truyền thông dễ dàng giữa các tiến trình cả trên mạng và trên một
máy tính. Mục tiêu của nó là che dấu càng nhiều càng tốt những gì xảy ra ở tầng truyền thông
phía dới.
TLI (Transport Layer Interface) Phát triển đầu tiên cho UNIX System V 3.0 có những hàm và thủ
tục tơng đơng với Socket nhng mô hình phức tạp hơn để đạt đợc tính mềm dẻo hơn.
I.2. Network I/O và file I/O
Hệ điều hành UNIX, có 6 lời gọi hệ thống vào ra file đó là:
open: Mở file.
creat: Tạo file.
close: Đóng file.
read: Đọc từ file.
write: Ghi file.
lseek: Chuyển con trỏ file.
1
Tiến trình ứng dụng
Th viện
Giao diện với nhân hệ điều hành
Giao diện với phần cứng
Phần cứng


Application
Socket Library
User
Kernel
Stream Head
SHOCKMOD
Transport Provider
TPI
Luận văn tốt nghiệp Nguyễn Nhật Bình
Và UNIX coi mỗi thiết bị đều nh một file, có thể đợc truy cập nh một file.
Tuy nhiên việc vào ra trên mạng với giao diện lập trình ứng dụng phức tạp hơn vì:
Mô hình Client-Server là không đối xứng, ta phải xác định chơng trình nào đóng vai trò Client, ch-
ơng trình nào đóng vai trò Server.
Một đối thoại trên mạng có thể là hớng kết nối hoặc không kết nối.
Một tiến trình con có thể sử dụng file descriptor của chơng trình cha truyền cho để làm việc với
file mà không cần biết đến tên file thực sự. Các ứng dụng trên mạng cần biết đợc đầu kia của kết
nối để chắc chắn rằng nó đợc phép đòi hỏi dịch vụ.
Trong phần nói về giao thức TCP/IP chúng ta đã biết để thiết lập kết nối cần nhiều tham số hơn
đối với file I/O, đó là giao thức (protocol), địa chỉ IP đích (Destination IP Address), địa chỉ IP
nguồn (Source IP Address), số hiệu cổng đích (Destination port number), số hiệu cổng nguồn
(Source port number).
Giao diện mạng phải hỗ trợ nhiều giao thức truyền thông ví dụ các chuẩn của tầng cao với tầng
thấp hơn.
I.3. Làm việc với Socket
Nh đã giới thiệu ở trên, Socket đợc gắn với khả năng truyền thông dễ dàng giữa các tiến trình cả trên
mạng và trên một máy tính. Và nó là che dấu càng nhiều càng tốt những gì xảy ra ở tầng truyền
thông phía dới. Chúng ta sẽ lựa chọn Socket để phát triển ứng dụng của mình trên mạng dựa trên mô
hình Client-Server.
I.3.1. Socket
Nói chung cơ chế socket tơng tự với cơ chế truy nhập tệp trong UNIX. Khi cần thiết tiến trình có thể

tạo ra một socket, hệ thống trả lại kết quả là một socket descriptor. Sự khác biệt giữa file descriptor
và socket descriptor ở chỗ file descriptor đợc gắn liền với một tệp hay thiết bị cố định còn socket
descriptor không bị gắn với một địa chỉ nào. Chơng trình có thể cung cấp địa chỉ tại mỗi lần truy nhập
2
Luận văn tốt nghiệp Nguyễn Nhật Bình
tới socket hay cũng có thể gắn socket descriptor với một địa chỉ nhất định. Do nó tơng thích với cơ
chế truy nhập tệp, nên vẫn có thể dùng các lệnh thông dụng nh read, write đối với socket.
Một Socket đợc dùng nh một endpoint. Mỗi Socket gắn với một nhóm
SHOCK_STREAM sử dụng cho dịch vụ hớng kết nối .
SHOCK_DGRAM sử dụng cho dịch vụ không kết nối.
SHOCK_RAW cung cấp truy cập trực tiếp vào giao thức để xây dựng công cụ quản trị ở mức
user.
SHOCK_SEQPACKET Giống nh SHOCK_STREAM nhng cung cấp biên giới các mesage.
SHOCK_RDM Cung cấp dịch vụ không kết nối đơn giản.
I.3.2. Địa chỉ Socket
Có hai loại địa chỉ đợc gán với một socket: Địa chỉ local và địa chỉ TCP/IP. Địa chỉ này đợc khai báo
là những bản ghi và đợc dùng làm tham số cho những lệnh hệ thống và thủ tục truy nhập socket. Địa
chỉ local là địa chỉ để xác định socket trong nội bộ máy.
Cấu trúc địa chỉ cục bộ đợc mô tả nh sau
Address family Address bytes 0-1
Address bytes 2-5
Address bytes 6-9
Address bytes 10-13
struct sock_addr
{
u_short sa_family; /* address family */
char sa_data[14]; /* up to 14 bytes address */
};
Trờng address family sẽ quyết định cấu trúc địa chỉ của trờng Address bytes phía sau vì socket hỗ trợ
cho nhiều giao thức khác nhau nên ứng với mỗi giao thức trờng địa chỉ sẽ có cấu trúc khác nhau.

Protocol family Description
PF_UNSPEC Unspecified family
PF_UNIX UNIX domain
PF_INET Internet protocols
PF_IMPLINK Arpanet IMP address
PF_PUP Old Xerox protocols
PF_CHAOS M.I.T. CHAOS protocols
PF_NS Xerox Network system protocols
PF_NBS NBS protocols
PF_ECMA European Computer Manual
PF_DATAKIT DATAKIT protocols
PF_CCITT CCITT protocols
PF_SNA IBM System Network Architeture
PF_DECnet DECnet protocols
PF_DLI DEC direct data link interface
PF_LAT LAN terminal interface
PF_HYLINK NSC Hyperchannel
PF_APPLETALK Apple Talk protocols
3
Luận văn tốt nghiệp Nguyễn Nhật Bình
PF_NIT Network interface tap
PF_802 IEEE 802.2
PF_OSI OSI protocols
PF_X25 CCITT X.25
PF_OSINET OSI protocols
PF_GOSIP U.S.government OSI protocols
Protocol Families
Địa chỉ TCP/IP đợc khai báo với tên sockaddr_in. Nó chứa số hiệu port và địa chỉ IP 32-bit.
Address family Protocol port
IP Address

Unused (0)
Unused (0)
struct in_addr /* 32-bit IP Addresss */
{
u_long s_addr; /* network byte order */
};
struct sockaddr_in
{
short sin_family; /* = AF_INET */
u_short sin_port; /* 16-bit port number */
struct in_addr sin_addr; /* 32-bit IP Addresss */
char sa_zero[14]; /*unused*/
};
I.3.3. Một số lời gọi tạo lập socket
Lời gọi socket():
Muốn làm việc với socket thì việc đầu tiên là phải tạo socket đó. Để làm việc đó cần gọi lệnh socket()
với các tham số cần thiết. Hàm trả lại một socket descriptor nếu thành công, -1 nếu có lỗi.
int socket (int family, int type, int protcol)
Tham số family xác định họ giao thức đợc sử dụng với socket nh đã nói đến ở trện.
AF_UNIX Giao thức nội bộ UNIX
AF_INER Giao thức Internet(TCP/IP)
AF_NS Giao thức Xeror NS
AF_IMPLINK Giao thức lớp IMP
Tham số type xác định kiểu của liên kết. Những kiểu có thể sử dụng là dạng stream có độ tin
cậy cao (SOCK_STREAM), dạng datagram (SOCK_DGRAM) hay dạng thô (SOCK_RAW) cho
phép truy nhập tới mức thấp của mạng.
Ví dụ:
AF_UNIX AF_INET AF_NS
SOCK_STREAM Có TCP Có
SOCK_DGRAM Có UDP Có

SOCK_RAW IP Có
4
Luận văn tốt nghiệp Nguyễn Nhật Bình
Do đó tham số thứ ba xác định chính xác giao thức nào đợc sử dụng cho socket. Tuy vậy trong rất
nhiều ứng dụng tham số này không đợc sử dụng.
Lời gọi bind()
Khi mới đợc tạo ra, socket không đợc gắn với bất cứ địa chỉ nào. Nói riêng với TCP/IP là nó cha đợc
gán với số hiệu port của tiến trình gửi, số hiệu port của tiến trình nhận cũng nh địa chỉ IP. Nhiều ch-
ơng trình không quan tâm đến số hiệu port và địa chỉ của nó, và dành cho phần mềm giao thức tự
gán. Tuy nhiên các chơng trình khác vẫn cần biết đến địa chỉ của mình. Lệnh bind gán thiết lập một
địa chỉ local cho socket và đăng ký nó với hệ thống.
int bind(int sock, struct sockaddr * localaddr, int addrlen)
Lời gọi bind() đợc sử dụng trong các trờng hợp sau:
Chơng trình server đăng ký một địa chỉ thông dụng với hệ thống. Mọi dữ liệu đến địa chỉ này sẽ
đợc chuyển cho nó.
Một chơng trình client đăng ký một địa chỉ đặc biệt.
Một chơng trình client có kiểu không kết nối (connectionless) muốn kiểm tra xem địa chỉ của nó
có hợp lệ hay không.
Lời gọi connect
Để thiết lập đợc một liên kết giữa client với server, tiến trình cần phải gọi lệnh connect.
int connect(int sock, struct sockaddr * seraddr, int addrlen)
Tham số lệnh này tơng tự đối với lệnh bind() nhng seraddr trỏ tới địa chỉ của server (tức là đầu kia
của liên kết).
Đối với các giao thức có liên kết (connection-oriented), connect() sẽ tạo lập một liên kết thực sự
giữa hai máy. Các thông tin đợc trao đổi nhằm thống nhất mọi tham số liên quan. Nó sẽ cha
thoát ra nếu nh cha thiết lập đợc liên kết hoặc cha nhận đợc thông báo lỗi.
Đối với các giao thức không liên kết (connectionless) lệnh connect() đơn giản chỉ cất giữ địa chỉ
server (biến seraddr) để tiến trình sau này sử dụng khi trao đổi dữ liệu. Với giao thức này việc gọi
lệnh connect() có thể bỏ qua nhng việc sử dụng nó sẽ tạo ra sự thuận tiện đối với ngời lập trình.
Sau khi đăng ký địa chỉ với hệ thống thì sẽ không cần phải xác định lại địa chỉ mỗi khi gửi đi các

datagram. Ngời sử dụng có thể dùng các lệnh read, write, recv, send tơng tự nh các socket có kết
nối.
Ngoài ra, connect còn kiểm tra xem có thực sự một tiến trình nào nhận thông tin mình sẽ gửi hay
không. Nếu địa chỉ gửi không tồn tại connect sẽ trả lại lỗi cho tiến trình gọi. Việc này làm cho tiến
trình có thể xử lý lỗi tốt hơn so với các giao thức không kết nối (ví dụ UDP). Một datagram có thể chứa
một địa chỉ sai và hoàn toàn không có ngời nhận.
Lời gọi listen()
5
Luận văn tốt nghiệp Nguyễn Nhật Bình
Ta sẽ xem xét một tiến trình server, tiến trình này đầu tiên tạo ra một socket, gắn nó với một port
thông dụng rồi chờ cho đến khi có một yêu cầu đợc gửi tới. Nếu nó là một liên kết kết nối thực sự,
hoặc nó phải xử lý quá lâu đối với mỗi yêu cầu, sẽ xảy ra trờng hợp là một yêu cầu mới sẽ tới trong
khi yêu cầu cũ cha đợc xử lý xong. Để tránh việc các yêu cầu mới bị từ chối, server phải khai báo với
phần mềm của giao thức tạo ra cho nó một hàng đợi các yêu cầu. Lệnh listen() sẽ khai báo hàng đợi
này.
int listen(int sock, int qlen)
Tham số sock là socket descriptor đợc dùng bởi server.
Tham số qlen quyết định chiều dài hàng đợi các yêu cầu. Giá trị tối đa của tham số này là 5.
Khi hàng đợi này đã đầy, hệ thống sẽ không chấp nhận thêm một yêu cầu nào khác. Mọi yêu cầu tới
sau đó sẽ bị huỷ bỏ. listen() chỉ áp dụng với socket kiểu STREAM.
Lời gọi accept()
Sau khi tiến trình server gọi các lệnh socket(), bind(), listen() để tạo ra một socket, gắn nó với một
port thông dụng, xác định chiều dài hàng đợi, server sẽ gọi lệnh accept() để tạo ra một kết nối hoàn
thiện.
int accept(int sock, struct sockaddr * addr, int addrlen)
Tham số addr dùng để trả lại địa chỉ của tiến trình gửi yêu cầu (client). accept() sẽ lấy yêu cầu đầu
tiên trong hàng đợi và tạo ra một socket mới có cùng thuộc tính với sock. Nếu trong hàng đợi không
có một yêu cầu nào thì nó sẽ chờ cho đến khi có một yêu cầu đợc gửi tới. Socket sock vẫn đợc giữ
nguyên do vậy server vẫn tiếp tục chấp nhận các yêu cầu khác gửi tới socket này.
Với cách tiếp cận tơng tác, server tự xử lý giải quyết yêu cầu sau đó đóng socket này lại và quay về

xử lý tiếp các yêu cầu sau đó.
Còn đối với phơng pháp đồng thời, sau khi lệnh accept() trả lại kết quả server sẽ sinh ra một tiến trình
con để giải quyết yêu cầu. Tiến trình con sẽ nhận đợc một bản sao của socket mới. Trong khi đó tiến
trình server sẽ lập tức đóng socket mới của nó sau khi tạo ra tiến trình con và trở lại gọi accept() để
nhận một yêu cầu mới.
Lời gọi close()
Khi một tiến trình thôi không sử dụng socket thì nó gọi lệnh close()
int close(int sock)
sock là socket cần huỷ bỏ. Khi một tiến trình kết thúc với mọi lý do, hệ thống sẽ đóng tất cả các
socket còn mở. Đối với các giao thức tin cậy, mặc dù socket đã bị đóng nhng kernel vẫn cố gắng gửi
đi các dữ liệu còn lại trong hàng đợi dữ liệu.
6
Luận văn tốt nghiệp Nguyễn Nhật Bình
I.3.4. Một số lời gọi gửi dữ liệu qua socket
Có 5 lời gọi đợc dùng để gửi dữ liệu qua socket. Các lệnh write, writev, send làm việc với các socket
đã kết nối vì chúng không cho phép khai báo địa chỉ ngời nhận.
Lời gọi send()
Lời gọi send có 4 tham số :
int send(int sock, char * buff, int len, int flag)
sock chỉ định socket đợc sử dụng,
buff trỏ tới vùng dữ liệu đợc gửi đi,
len xác định số byte trong buff đợc gửi đi.
flag cho phép ngòi gửi chọn một số cách thức để gửi dữ liệu ví dụ nh gửi dữ liệu out-of-band...
Các tham số này khác nhau đối với mỗi loại socket. send() trả lại mã lỗi cho chơng trình gọi để chơng
trình biết đợc thao tác có thành công hay không.
Lời gọi write()
Do cách thức truy nhập tới socket tơng tự truy nhập đến file nên có thể dùng lệnh hệ thống write để
gửi dữ liệu qua socket.
int write(int fd, char * buff, int len)
Tham số fd có thể là một socket descriptor hoặc file descriptor.

Lời gọi writev()
Để gửi đi một danh sách các khối dữ liệu ta dùng
int writev(int fd, struct iovec iovector[], int vectorlen)
Các lời gọi sendto(), sendmsg()
Đợc dùng cho các socket không kết nối. Hai lệnh này yêu cầu phải cung cấp địa chỉ ngời nhận.
int sendto(int sock, char * buff, int len, int flag, struct sockaddr * destaddr, int addrlen)
Bốn tham số đầu giống nh bốn tham số của send().
Hai tham số sau là địa chỉ của ngời nhận và độ dài của địa chỉ.
Do sendto() có quá nhiều tham số, lập trình viên có thể sử dụng lời gọi sendmsg()
int sendmsg(int sock, struct msghdr msg[], int flag)
Với tham số msg là một cấu trúc có chứa địa chỉ và danh sách nhiều đoạn dữ liệu cần gửi đi.
7
Luận văn tốt nghiệp Nguyễn Nhật Bình
I.3.5. Một số lời gọi nhận dữ liệu từ socket
Tơng ứng với 5 lệnh để gửi dữ liệu có 5 lệnh dùng để nhận dữ liệu với tham số và cơ chế hoàn toàn
giống nhau.
int recv(int sock, char * buff, int len, int flag)
int read(int fd, char * buff, int len)
int readv(int fd, struct iovec iovector[], int * vectorlen)
int recvfrom(int sock, char * buff, int len, int flag, struct sockaddr * destaddr, int *addrlen)
int recvmsg(int sock, struct msghdr msg[], int flag)
II. Mô hình Client-Server
Theo cách nhìn của ngời lập trình, TCP/IP giống nh hầu hết các giao thức truyền thông khác cung
cấp cơ chế cơ bản để truyền dữ liệu. Đặc biệt, TCP/IP cho phép ngời lập trình thiết lập truyền thông
giữa hai chơng trình ứng dụng và truyền dữ liệu qua lại. TCP/IP cung cấp kết nối bình đẳng giữa các
ứng dụng kể cả các ứng dụng chạy trên cùng một máy.
Một phát triển của mô hình peer-to-peer là mô hình Client-Server đã trở thành mô hình cơ bản đợc sử
dụng trên mạng máy tính. Chơng trình Server là một chơng trình chờ đợi kết nối từ chơng trình Client
và cung cấp dịch vụ cho Client.
Mô hình đợc mô tả nh sau:

Tiến trình Server đợc khởi động trên một hệ thống nào đó sau đó chờ đợi một tiến trình Client kết
nối đến yêu cầu dịch vụ.
Tiến trình Client đợc khởi động trên cùng hệ thống máy với chơng trình Server hoặc từ một hệ
thống khác kết nối với hệ thống chủ thông qua mạng. Client gửi yêu cầu qua mạng tới tiến trình
Server đòi hỏi một số dịch vụ nh:
Trả lại ngày giờ cho Client
In một file cho Client
Đọc hoặc ghi file vào hệ thống file của Server
Cho phép Client login vào hệ thống Server
Chạy chơng trình của Client trên hệ thống Server
Sau khi cung cấp dịch vụ cho Client, Server tiếp tục nghỉ và chờ đợi kết nối khác.
Chúng ta có thể chia tiến trình Server làm 2 kiểu:
Tơng tác (Interative Server): Khi Client đòi hỏi những dịch vụ đã đăng ký trớc với khoảng thời
gian thực hiện nhỏ, Server tự làm công việc đó ví dụ dịch vụ trả lại ngày giờ.
Đồng thời (Concurrent Server): Với những yêu cầu đòi hỏi thời gian thực hiện lớn, tiến trình
Server sinh một tiến trình con để thực hiện yêu cầu còn nó tiếp tục chờ đợi yêu cầu khác. Dịch vụ
in file, đọc-ghi file đợc thực hiện theo kiểu này.
8
recvfrom()
recvfrom()
bind()
bind()
socket()
sendto()
Server(connectionless protocol)
block until data received from client
process request
sendto()
socket()
Client

data (reply)
data (request)
Lời gọi socket cho mô hình client-server không kết nối
Luận văn tốt nghiệp Nguyễn Nhật Bình
II.1. Mô hình Client-Server sử dụng dịch vụ không kết nối
Với mô hình không kết nối, client không kết nối với server mà chỉ gửi dữ liệu đến sử dụng lời gọi
sento(), ngợc lại, server sử dụng lời gọi recvfrom() chờ đợi dữ liệu từ client chuyển đến. Lời gọi
recvfrom() trả lại địa chỉ của client, nhờ đó server có thể gửi kết quả lại cho client.
9
accept()
listen()
bind()
socket()
write()
write()
Server(connection-oriented protocol)
Connect()
read()
read()
socket()block until connection from client
Process request
Connection establishment
data (reply)
data (request)
Client
Lời gọi socket cho mô hình client-server h-ớng kết nối
Luận văn tốt nghiệp Nguyễn Nhật Bình
II.2. Mô hình Client-Server sử dụng dịch vụ hớng kết nối
Với mô hình Client-Server sử dụng dịch vụ hớng kết nối, đầu tiên Server đợc khởi động và chờ đợi
một kết nối từ client.

Sau khi kết nối đợc thiết lập, hai bên luân phiên nhau gửi nhận dữ liệu thông qua đờng truyền.
III. Xây dựng chơng trình truyền tệp
III.1. Thiết kế và cài đặt chơng trình
III.1.1. Giao thức ứng dụng đợc xây dựng và sử dụng trong chơng trình
Bản thân giao thức TCP là một giao thức hớng kết nối và đáng tin cậy, giao thức này đảm bảo dữ liệu
truyền vào socket đầy đủ, nhng để tăng cờng tính tin cậy của chơng trình ứng dụng và để kiểm soát
việc truyền dữ liệu nhất là trên các mạng có độ trễ lớn hay những mạng thờng xuyên xảy ra hiện tợng
quá tải, một giao thức ứng dụng riêng đợc xây dựng cho chơng trình.
Gói tin của giao thức ứng dụng đợc mô tả nh sau:
0 1 2 Dữ liệu tối đa 4094 byte
Size Data
10
ServerClient
Gửi lệnh
Nhận lệnh và thi hành
Nhận thông báo
Gửi thông báo hoàn thành lệnh hoặc báo lỗi
Server
Client
Gửi lệnh
Nhận lệnh và thi hành
Nhận thông báo
Nhận dữ liệu ở kênh dữ liệu tới khi gói tin có độ dài là 0
Gửi thông báo có dữ liệu cần truyền
Gửi lần l-ợt các gói tin kết thúc bởi một gói có độ dài là 0
Luận văn tốt nghiệp Nguyễn Nhật Bình
Size dài 2 byte chứa độ dài của phần dữ liệu của gói tin.
Data chứa dữ liệu, trờng này có độ dài tối đa là 4094 byte vì giao thức sử dụng gói tin dài tối đa
4096 byte.
Việc sử dụng các kết nối:

Chơng trình sử dụng hai kết nối, một để truyền lệnh và một để truyền dữ liệu giữa client và server.
Kênh truyền điều khiển dùng để truyền các lệnh và các thông báo có tính chất điều khiển, điều
này làm giảm tính phức tạp trong việc phân tích và xử lý các lệnh của chơng trình.
Kênh truyền dữ liệu đợc thiết lập ngay trong quá trình tạo kết nối giữa tiến trình client và tiến trình
server và đợc dùng đến mỗi khi có dữ liệu cần truyền nhận giữa client và server. Các khối dữ liệu
có thể đợc chia nhỏ thành các gói tin và truyền trên kênh dữ liệu, kết thúc một khối dữ liệu là một
gói tin có độ dài bằng 0.
Việc sử dụng hai kênh truyền
Có 3 loại lệnh trong chơng trình sử dụng các kênh truyền nh sau:
Client gửi lệnh đến server và nhận về một thông báo trên kênh điều khiển ví dụ thông báo lỗi
hoặc hoàn thành lệnh.
Client gửi lệnh đến server và nhận về một thông báo có dữ liệu truyền Openning data port. Khi
đó, client bắt đầu nhận dữ liệu trên kênh dữ liệu cho tới khi nhận đợc một gói tin có độ dài là 0.
11
ServerClient
Gửi yêu cầu truyền dữ liệu
Nhận lệnh
Nhận và thông báo với ng-ời sử dụng số byte truyền
Nhận dữ liệu ở kênh dữ liệu tới khi gói tin có độ dài là 0
Gửi thông báo chấp nhận
Thông báo số byte đã nhận
Gửi lần l-ợt các gói tin kết thúc bởi một gói có độ dài là 0
Luận văn tốt nghiệp Nguyễn Nhật Bình
Client gửi lệnh yêu cầu truyền tệp lên server, server gửi lại thông báo chấp nhận. Client ghi dữ
liệu cần truyền vào kênh dữ liệu, sau khi ghi xong, client chờ đợi một thông báo của server trên
kênh điều khiển truyền lại số lợng byte đã nhận và thông báo trên màn hình của ngời sử dụng.
Quá trình truyền nhận thông tin trên kênh dữ liệu cũng có thể đợc điều khiển trực tiếp trên kênh
điều khiển ví dụ dừng truyền.
III.1.2. Cài đặt chơng trình
Chơng trình truyền tệp đợc xây dựng dựa trên mô hình client-server sử dụng th viện socket, giao thức

lớp dới là giao thức hớng kết nối TCP. Tiến trình server hoạt động theo kiểu đồng thời (concurrent),
server nghe ở cổng 1998, khi có một tiến trình client kết nối đến, server nhận số hiệu cổng của
client, sinh tiến trình con để phục vụ còn bản thân tiến trình cha tiếp tục quay lại nghe. Tiến trình
server phục vụ tạo một kết nối lệnh để truyền lệnh và một kết nối dữ liệu để truyền các khối dữ liệu
giữa client và server.
Phần server chạy trên các máy chủ Unix, Windows NT phục vụ cho phần client chạy trên các máy
Dos, Windows và Unix. Chơng trình hoạt động gần giống FTP nhng có một số tính năng nâng cao:
Thực hiện lệnh từ xa với EXEC: Chơng trình server nhận lệnh gửi tới từ client, thực hiện lệnh đó
và gửi trả kết quả vào kênh truyền, chơng trình client đọc và hiển thị kết quả đó trên màn hình
của ngời sử dụng.
Thực hiện lệnh của hệ điêu hành trên máy trạm !CMD: Một số lệnh của hệ điều hành có thể đợc
thực hiện trên máy trạm, chúng đợc tiến trình client giải quyết bằng cách gọi chơng trình thông
dịch của hệ điều hành.
Khả năng thay đổi kích thớc bộ đệm với BUFSIZ kích thớc của bộ đệm có thể đợc thay đổi bằng
cách thay đổi biến môi trờng chứa kích thớc bộ đệm. Việc này làm tăng năng suất của việc truyền
thông tin trên mạng.
Một số thao tác với th mục trên máy chủ nh tạo th mục, xoá th mục đợc thực hiện bằng cách gọi
các lệnh của hệ điều hành Unix hoặc những hàm mức thấp trong th viện của C.
12
Luận văn tốt nghiệp Nguyễn Nhật Bình
Chơng trình còn cung cấp một số lệnh làm việc trực tiếp với tệp nh OPEN, LSEEK, READ,
WRITE... những lệnh này sử dụng th những lời gọi mức thấp của hệ thống.
Sau đây là những lệnh đã cài đặt trên server
Lệnh Mô tả
EXEC command [option]
Chạy một lệnh Unix
USER username [PASS password]
Đăng nhập hệ thống
PASSWD password
Nhập password

CHPWD newpassword
Đổi password
PORT portnumber
Đăng ký một cổng truyền dữ liệu
ABORT
Loại bỏ quá trình truyền
PWD
Lệnh đổi th mục
LIST [option] [directory]
Lệnh xem th mục
CHDIR [directory]
Lệnh đổi th mục
MKDIR directory [mode]
Tạo th mục mới
RMDIR directory
Xoá th mục
UNLINK filename
Xoá tệp
OPEN path openflag [mode]
Mở tệp
LSEEK fildes offset whence
Chuyển con trỏ tệp
READ fildes nbytes
Đọc từ tệp
WRITE fildes nbytes
Ghi tệp
LOCKF fildes mode size
Khoá tệp
CLOSE filedes
Đóng tệp

TMPNAM [path[prefix]]
Tạo một tệp tạm thời
PUT filename
Truyền tệp lên máy chủ
APPEND filename
Mở tệp để append
GET filename
Lấy tệp từ máy chủ
HELP
Trợ giúp
UNIX
Hoạt động ở mode Unix
TNET
Hoạt động ở mode Tnet
QUIT
Thoát
UMASK [mode]
Đặt mặt nạ mode cho file truyền
FMODE filename
Xem mode của file
FSIZE filename
Xem độ dài của file
BUFSIZ size_of_buffer
Đặt lại kích thớc cho bộ đệm
REXEC host user passwd command
Chạy một lệnh từ xa
Phần client giao tiếp với ngời sử dụng, nhận lệnh, phân tích lệnh, xử lý hoặc gửi cho server, nhận và
trả kết quả lại cho ngời sử dụng.
(Văn bản chơng trình client đợc in trong phần phụ lục C)
III.2. Một số vấn đề nảy sinh trong quá trình thực hiện và cách giải quyết

III.2.1. Vấn đề chuyển đổi tệp giữa hai hệ điều hành.
Do khái niệm về tệp và sự quản lý truy nhập ở hai hệ điều hành DOS và UNIX có nhiều điểm khác
nhau nên sự chuyển đổi tệp giữa hai hệ điều hành gặp phải một số vấn đề.
Các tệp tin trên DOS hoàn toàn không có các thông tin về quyền sở hữu hay quyền truy nhập nên
thông tin này sẽ bị mất khi sao chép một tệp từ máy UNIX sang một máy DOS.
13
Luận văn tốt nghiệp Nguyễn Nhật Bình
Ngoài ra một vấn đề hết sức quan trọng và cũng khó có cách giải quyết tối u là vấn đề tên tệp. Tên
tệp trên UNIX có thể dài tới 14 ký tự (đối với UNIX System V) hoặc hơn nữa, các ký tự có thể là chữ in
hoa, chữ thờng hay các ký tự đặc biệt đều đợc chấp nhận. Các th mục trong đờng dẫn của UNIX đợc
phân cách bởi dấu '/'. Trong khi đó tên tệp của DOS chỉ đợc phép dài tối đa 8 ký tự cộng với 3 ký tự
của phần mở rộng và bị hạn chế toàn bộ là chữ in hoa không sử dụng chữ thờng cùng với hàng loạt
dấu và ký tự đặc biệt. Các th mục trong đờng dẫn đợc phân cách bởi dấu '\'. Cho nên một ánh xạ 1-1
giữa hai loại tên tệp là không thể tồn tại. Nếu có một hàm nào đó thực hiện đợc ánh xạ này thì sau khi
chuyển một tệp từ máy UNIX tới máy DOS, tên tệp đích sẽ hoàn toàn xa lạ với tên tệp nguồn gây ra
khó khăn cho ngời sử dụng.
Ví dụ, ta muốn có một tiện ích thực hiện việc backup một số tệp trên máy UNIX sang máy DOS. Ta
sẽ đơn giản chuyển các tệp đó sang máy DOS nhng khi cần chuyển các tệp này về vị trí cũ thì ta
không thể xác định chính xác vị trí cũ của tệp và không thể phục hồi lại đầy đủ tên của tệp. Nếu dùng
một hàm nào đó để tạo ra ánh xạ 1-1 thì khi sao chép sang máy DOS sẽ tạo ra những tên tệp đặc
biệt rất khó cho việc quản lý.
Với bài toán này UNIX có tiện ích tar giải quyết bằng cách gom tất cả các tệp vào thành một tệp
kèm theo thông tin chi tiết về tệp đó, khi cần, có thể phục hồi lại tệp một cách chính xác. Nhng
tiện ích này không thể áp dụng cho mọi bài toán ví dụ cần đọc và xử lý tệp dới môi trờng DOS...
Có một giải pháp tạm thời cho vấn đề này là phải cắt bỏ phần đằng sau của tên tệp trên UNIX.
Đây cũng chính là giải pháp đối với tên tệp dài của Windows 95 khi các tệp này đợc truy nhập
bởi DOS 6.x (hoặc các phiên bản DOS trớc). Với cách làm này chúng ta phải chú ý tới sự trùng
tên sau khi cắt bỏ phần đuôi và xử lý một số ký tự đặc biệt còn lại.
Ví dụ : Hai tệp
testdata001.dat và testdata002.dat

Có thể sẽ bị cắt thành testdata.dat và hai tệp sẽ bị trùng tên nhau, một trong hai tệp sẽ không thể tồn
tại.
Một giải pháp tơng tự nh trong Windows 95 sẽ đợc sử dụng đó là chuyển hai tệp trên thành
testda~1.dat và testda~2.dat
Giải pháp đặt tên cho các tệp trên máy UNIX tơng tự nh trên máy DOS là một giải pháp tồi. Nó
không tận dụng tối đa khả năng của hệ điều hành là tên tệp linh động hơn. Nhng ta nhận thấy
rằng phơng pháp này đôi khi cũng tỏ ra có hiệu quả đối với các ứng dụng đặc biệt. Ví dụ : phần
mở rộng 3 ký tự của tên tệp đợc dùng để xác định nội dung tệp đợc dùng khá rộng rãi trên cả các
hệ điều hành có tên tệp dài nh UNIX, Windows 95...
Một giải pháp khác là việc thay thế hệ điều hành DOS bằng hệ điều hành Windows 95. Trong
Windows 95 tên tệp có thể dài hơn (tới 255 ký tự) và có thể chứa một số ký tự mà DOS không
cho phép nh dấu trống, dấu chấm... Việc chuyển đổi tên tệp sẽ đơn giản chỉ là xử lý một số trờng
hợp các ký tự đặc biệt. Với sự phát triển hiện nay hệ điều hành DOS đang dần bị thay thế bởi
Windows 95 (không chỉ bởi đặc tính tên tệp mà bởi nhiều tính năng vợt trội của Windows 95) thì
việc thay thế này hoàn toàn thích hợp.
14

×