Tải bản đầy đủ (.doc) (12 trang)

Lập trình mạng bằng pocket PC-part 6 pps

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 (118.73 KB, 12 trang )

Kết nối đến Server ( từ Client ) :
Khi bạn đã tạo một socket, bạn có thể dùng nó để thiết lập một kết nối đến
server . Ta dùng hàm connect() để thực hiện việc này:
int connect (SOCKET s, const struct sockaddr *name, int namelen ).
Tham số đầu tiên, s, xác định socket descriptor được trả về bởi hàm socket() .
Tham số name là socket address structure , SOCKADDR_IN , xác định server mà
ta định kết nối .Tham số namelen là chiều dài của bộ đệm dành cho tham số name
Nếu ta thành công trong việc thiết lập một kết nối đến Server xác định bởi tham số
name , thì hàm này sẽ trả về giá trị 0, ngược lại lỗi một SOCKET_ERROER sẽ
xảy ra. Để tìm xem thông tin vì sao không thiết lập được kết nối ta gọi hàm
WSAGetLastError () . Nên nhớ rằng ta không thể gọi hàm connect() trên một
socket đã được kết nối.
Một khi một kết nối đã được thiết lập, thì socket sẵn sàng gửi và nhận dữ
liệu . Chú ý rằng: Nếu một kết nối đã bị đứt (broken) trong lúc Client và Server
đang truyền tin với nhau thì ứng dụng của ta cần phải bỏ socket cũ và tạo một
socket mới để thiết lập lại việc truyền tin giữa Client và Server.
Ví dụ sau trình bày cách kết nối đến Server :
// First, get the host information
HOSTENT *hostServer = gethostbyname("www.microsoft.com");
if(hostServer == NULL) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Set up the target device address structure
SOCKADDR_IN sinServer;
memset(&sinServer, 0, sizeof(SOCKADDR_IN));
sinServer.sin_family = AF_INET;
sinServer.sin_port = htons(80);
sinServer.sin_addr =
*((IN_ADDR *)hostServer->h_addr_list[0]);
// Connect with a valid socket


if(connect(s, (SOCKADDR *)&sinServer, sizeof(sinServer)) ==
SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Do something with the socket
closesocket(s);
Gửi và nhận dữ liệu :
Chúng ta đã thiết lập một kết nối đến server, đã sẵn sàng cho việc gửi và
nhận dữ liệu giữa hai máy trên mạng. Trên một kết nối socket, dữ liệu có thể được
truyền cả hai hướng, Server và Client có thể dùng cùng phương thức để truyền tin
với nhau.
Để truyền dữ liệu trên một kết nối socket ta dùng phương thức send(), được
xác định như sau:
int send (SOCKET s, const char *buf, int len, int flags) ;
Tham số s là socket handle mà ta đã dùng với hàm connect () ở trên, và nó
được tạo lúc đầu bằng hàm socket(). Tham số buf là một con trỏ, trỏ đến bộ đệm
chứa dữ liệu mà ta muốn gửi, và chiều dài của nó được xác định bởi tham số len.
Tham số cuối cùng, flags, được dùng để xác định cách dữ liệu được gửi, có giá trị
là 0 hoặc MSG_DONTROUTE. Thông thường, tham số này được thiết lập là 0, và
MSG_DONTROUTE chỉ dùng cho việc kiểm tra hoặc định đường đi cho thông
điệp.
Giá trị trả về của hàm send() là số byte thực sự được gửi trên mạng hoặc một
SOCKET_ERROR nếu có lỗi trong việc truyền dữ liệu.
Để nhận dữ liệu trên một socket, ta dùng hàm recv():
int recv ( SOCKET s , char *buf , int len , int flags ) ;
Tương tự như trên, tham số s chỉ socket mà chúng ta thiết lập để nhận dữ
liệu . Tham số thứ hai, buf, là một bộ đệm để nhận dữ liệu, kích thước của nó được
xác định bởi tham số len. Cuối cùng, tham số flags, thường được thiết lập là 0.
Giá trị trả về của hàm recv() là số byte nhận được hoặc là 0 nếu kết nối bị

đóng . Hàm cũng sẽ trả về một SOCKET_ERROR nếu có lỗi xảy ra .
Chú ý rằng: cả hai hàm send() và recv() không luôn luôn đọc hoặc ghi
chính xác số lượng dữ liệu mà ta đã yêu cầu. Điều này là do TCP/IP cấp phát một
số lượng không gian bộ đệm có hạn cho hàng đợi dữ liệu đi và vào, và thường thì
bộ đệm này đầy khá nhanh. Ví dụ, nếu chúng ta yêu cầu một file 10 MB từ một
trang web, hàng đợi dữ liệu vào của ta sẽ khóa cho đến khi ta đọc được dữ liệu từ
hàng đợi này (dùng hàm receive()). Việc truyền dữ liệu cũng tương tự như thế, cho
nên chúng ta cần đảm bảo rằng: tất cả dữ liệu ra của chúng ta đã được gửi.
Ví dụ sau thể hiện việc gửi dữ liệu bộ đệm trên TCP:
// Send a request to the server
char cBuffer[1024] = "";
int nBytesSent = 0;
int nBytesIndex = 0;
// Set up the buffer to send
sprintf(cBuffer, "GET / HTTP/1.0\r\n\r\n");
int nBytesLeft = strlen(cBuffer);
// Send the entire buffer
while(nBytesLeft > 0) {
nBytesSent = send(s, &cBuffer[nBytesIndex], nBytesLeft, 0);
if(nBytesSent == SOCKET_ERROR)
break;
// See how many bytes are left. If we still need to send, loop
nBytesLeft -= nBytesSent;
nBytesIndex += nBytesSent;
}
Ví dụ:
Ví dụ sau trình bày cách dùng socket TCP để tạo một client cơ bản để kết nối
với một trang web, gửi yêu cầu, và nhận trang web HTML mặc định. Khi thực
hiện thành công, nó sẽ nội dung trên Message Box. Bộ đệm thực sự được trả về từ
yêu cầu này được trình bày trong hình sau:

Hình 3.40
// Initialize Winsock
WSADATA wsaData;
memset(&wsaData, 0, sizeof(WSADATA));
if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
return FALSE;
// Create a connection-oriented socket
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Check to see if we have a valid socket
if(s == INVALID_SOCKET) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Get the host information
HOSTENT *hostServer = gethostbyname("www.microsoft.com");
if(hostServer == NULL) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Set up the target device address structure
SOCKADDR_IN sinServer;
memset(&sinServer, 0, sizeof(SOCKADDR_IN));
sinServer.sin_family = AF_INET;
sinServer.sin_port = htons(80);
sinServer.sin_addr =
*((IN_ADDR *)hostServer->h_addr_list[0]);
// Connect
if(connect(s, (SOCKADDR *)&sinServer, sizeof(sinServer)) ==
SOCKET_ERROR) {
int iSocketError = WSAGetLastError();

return FALSE;
}
// Send a request to the server
char cBuffer[1024] = "";
int nBytesSent = 0;
int nBytesIndex = 0;
// Set up the buffer to send
sprintf(cBuffer, "GET / HTTP/1.0\r\n\r\n");
int nBytesLeft = strlen(cBuffer);
// Send the entire buffer
while(nBytesLeft > 0) {
nBytesSent = send(s, &cBuffer[nBytesIndex], nBytesLeft, 0);
if(nBytesSent == SOCKET_ERROR)
break;
// See how many bytes are left. If we still need to send, loop
nBytesLeft -= nBytesSent;
nBytesIndex += nBytesSent;
}
// Get the response
TCHAR tchResponseBuffer[1024] = TEXT("\0");
char cResponseBuffer[1024] = "";
BOOL fBreak = FALSE;
int nBytesReceived = 0;
while(!fBreak) {
nBytesReceived = recv(s, &cResponseBuffer[0], 1024, 0);
if(nBytesReceived == SOCKET_ERROR)
break;
// Convert the data from ANSI to Unicode
mbstowcs(tchResponseBuffer, cResponseBuffer, nBytesReceived);
// Show the MessageBox

MessageBox(NULL, tchResponseBuffer, TEXT("Web Output"), MB_OK);
// Check to see if this is the end of the HTTP response by
// looking for \r\n\r\n
if(_tcsstr(tchResponseBuffer, TEXT("\r\n\r\n")))
fBreak = TRUE;
// Clear the buffers
memset(tchResponseBuffer, 0, 1024);
memset(cResponseBuffer, 0, 1024);
}
closesocket(s);
WSACleanup();
Server:
Nhận một kết nối vào ( Server ) :
Sự khác nhau cơ bản của việc truyền dữ liệu giữa luồng kết nối Server và
Client là cách kết nối được thiết lập (Client thì tạo kết nối, còn Server thì lắng
nghe kết nối). Mặt khác, cả hai đều sử dùng phương thức send() và recv() để trao
đổi dữ liệu giữa hai máy. Chúng ta đã tìm hiểu ở phía Client, giờ đây ta bắt đầu
tìm hiểu cách tạo một ứng dụng theo yêu cầu của những dịch vụ kết nối vào (hình
thành do gọi hàm connect()). Điều đầu tiên mà chúng ta cần làm là tạo một socket;
giống như ta đã làm ở phía Client bằng cách gọi hàm socket().
Sau khi đã tạo socket rồi, thay vì kết nối đến một Server, ta để socket mới
này ở trạng thái lắng nghe kết nối vào. Để làm được việc đó, chúng ta cần kết buộc
(bind) socket mới được tạo này với một địa chỉ cục bộ. Để tạo kết buộc này ta
dùng hàm bind()
int bind( SOCKET s, const struct sockaddr *addr, int namelen ) ;
Tham số đầu tiên, s, là một handle của socket được tạo bởi hàm socket(), và
ta sẽ dùng socket này để chở kết nối. Tham số addr là một con trỏ, trỏ đến address
buffer, được xác định bởi giao thức mà ta muốn sử dụng. Nếu ta muốn dùng giao
thức TCP/IP chuẩn, thì chúng ta sẽ dùng bộ đệm SOCKADDR_IN. Nếu dùng giao
thức hồng ngoại thì sử dùng SOCKADDR_IRDA. Tham số cuối cùng, namelen,

chỉ kích thước của cấu trúc địa chỉ (address structure) mà tham số addr đã dùng.
Nếu không có lỗi, hàm bind() sẽ trả về 0, ngược lại, một SOCKET_ERROR
sẽ xuất hiện.
Ví dụ sau sẽ kết buộc kết nối TCP trên cổng 80 đến một socket cho tất cả địa
chỉ IP trên thiết bị.
SOCKADDR_IN sListener;
memset(&sListener, 0, sizeof(SOCKADDR_IN));
// Set up the port to bind on
sListener.sin_family = AF_INET;
sListener.sin_port = htons(80);
sListener.sin_addr.s_addr = htonl(INADDR_ANY);
// Create a TCP socket
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(s == INVALID_SOCKET)
return FALSE;
// Bind to the socket
if(bind(s, (SOCKADDR *)&sListener, sizeof(sListener)) ==
SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
Chú ý rằng: Ta đã dùng địa chỉ IP INADDR_ANY thay vì địa chỉ IP của
Adapter . Dùng INADDR_ANY làm cho chúng ta có thể kết buộc socket vào tất
cả những địa chỉ IP có sẵn trên thiết bị của chúng ta, do đó những kết nối vào trên
bất kỳ giao diện nào cũng được chấp nhận bởi socket của chúng ta.
Khi socket đã được kết buộc vào địa chỉ (hoặc nhiều địa chỉ), chúng ta cần
đặt socket này ở chế độ lắng nghe. Điều này làm cho socket có thể chờ những kết
nối vào
int listen( SOCKET s , int backlog) ;
Tham số s chỉ socket đã kết buộc. Tham số backlog xác định kích thước của

hàng đợi cho kết nối vào, thường được thiết lập là SOMAXCONN (trên Pocket
PC hiện nay chỉ giới hạn cho hai kết nối). Hàng đợi backlog được dùng khi cùng
lúc có nhiều kết nối vào. Khi hàng đợi đầy, tất cả những yêu cầu khác sẽ bị từ chối
cho đến khi một yêu cầu kết nối được lấy ra khỏi hàng đợi bởi hàm accept().
Nếu có lỗi hàm listen() sẽ trả về giá trị SOCKET_ERROR, ngược lại là giá
trị 0
Cuối cùng để nhận socket của kết nối vào, chúng ta cần gọi hàm accept(), được
xác định như sau.
SOCKET accept( SOCKET s, struct sockaddr *addr, int * addrlen);
Tham số s chỉ socket mà chúng ta đã đặt ở chế độ lắng nghe ở trên. Tham
số addr chỉ bộ đệm dùng để nhận hoặc là một cấu trúc SOCKADDR_IN hoặc là
SOCKADDR_IRDA tùy thuộc vào giao thức mà socket đã dùng, chứa những
thông tin về kết nối vào. Tham số cuối cùng, addrlen, chỉ kích thước của cấu trúc
addr.
Chú ý rằng : phương thức accept() không trả về giá trị ngay lập tức. Điều này
là do accept() là hàm khóa, nghĩa là nó sẽ không trả về giá trị cho đến khi có kết
nối từ một client hoặc socket lắng nghe bị hủy (ta cũng có thể thiết lập một tùy
chọn socket để đặt nó ở chế độ không khóa). Khi hàm accept() trả về, thì giá trị
của nó hoặc là một socket handle mới cho client kết nối vào, hoặc là một lỗi
SOCKET_ERROR. Tất cả những thông tin về client kết nối vào sẽ được thể hiện
ở socket handle mới này, trong khi socket ban đầu tiếp tục lắng nghe nhiều kết nối
khác.
Ví dụ:
Ví dụ sau thể hiện việc Server lắng nghe kết nối vào của một Client yêu cầu
một trang Web dùng giao thức HTTP, và trả về cho Client một hồi đáp.
// Initialize Winsock
WSADATA wsaData;
memset(&wsaData, 0, sizeof(WSADATA));
if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0)
return FALSE;

// Create a connection-oriented socket
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Check to see if we have a valid socket
if(s == INVALID_SOCKET) {
int iSocketError = WSAGetLastError();
return FALSE;
}
SOCKADDR_IN sListener;
memset(&sListener, 0, sizeof(SOCKADDR_IN));
// Setup the port to bind on
sListener.sin_family = AF_INET;
sListener.sin_port = htons(80);
sListener.sin_addr.s_addr = htonl(INADDR_ANY);
// Bind to the socket
if(bind(s, (SOCKADDR *)&sListener, sizeof(sListener)) ==
SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Listen for incoming connections
if(listen(s, SOMAXCONN) == SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Wait for a connection
SOCKADDR_IN sIncomingAddr;
memset(&sIncomingAddr, 0, sizeof(SOCKADDR_IN));
int iAddrLen = sizeof(SOCKADDR_IN);
SOCKET sIncomingSocket = accept(s, (SOCKADDR *)
&sIncomingAddr, &iAddrLen);

if(sIncomingSocket == SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// We have an incoming socket request
char cResponseBuffer[1024] = "";
int nBytesReceived = 0;
// Get a basic request. In reality, we would want to check
// the HTTP request to see if it's valid, but let's just
// send a simple response.
nBytesReceived = recv(sIncomingSocket, &cResponseBuffer[0],
1024, 0);
if(nBytesReceived == SOCKET_ERROR) {
int iSocketError = WSAGetLastError();
return FALSE;
}
// Send out a response
char cBuffer[1024] = "";
int nBytesSent = 0;
int nBytesIndex = 0;
// Setup the buffer to send
sprintf(cBuffer, &"HTTP/1.0 200 OK\r\n\r\nTest
Response\r\n\r\n");
int nBytesLeft = strlen(cBuffer);
// Send the entire buffer
while(nBytesLeft > 0) {
nBytesSent = send(sIncomingSocket, &cBuffer[nBytesIndex],
nBytesLeft, 0);
if(nBytesSent == SOCKET_ERROR)
break;

// See how many bytes are left. If we still need to send, loop
nBytesLeft -= nBytesSent;
nBytesIndex += nBytesSent;
}
// Close the sockets
closesocket(sIncomingSocket);
closesocket(s);
WSACleanup();

×