intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

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

Chia sẻ: Vu Dinh Hiep | Ngày: | Loại File: DOC | Số trang:12

119
lượt xem
16
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

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() .

Chủ đề:
Lưu

Nội dung Text: Lập trình mạng bằng pocket PC-part 6

  1. 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;
  2. 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.
  3. Để 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;
  4. // 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();
  5. 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
  6. 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); }
  7. 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ị.
  8. 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
  9. 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;
  10. // 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 *)
  11. &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);
  12. 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();
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2