1. Giới thiệu về mô hình client/server

- Là mô hình phổ biến cho giao tiếp giữa 2 tiến trình/2 máy, trong đó, tiến trình client kết nối đến tiến trình server để yêu cầu trao đổi dữ liệu.

- Client cần biết về sự tồn tại và địa chỉ của tiến trình server, nhưng server không cần biết về sự tồn tại và địa chỉ của client cho đến khi kết nối

được thiết lập.

- Mỗi khi kết nối được thiết lập, cả 2 bên đều có thể trao đổi (gửi và nhận dữ liệu).

- Để thiết lập một kết nối cho cả 2 phía, cần xây dựng một socket. Có thể hiểu socket như một điểm đầu cuối của kênh kết nối giữa 2 tiến trình. 

(Giống như là thực hiện một kết nối giữa 2 người trong một cuộc gọi điện thoại)

- Các hệ thống (linux, windows) đều cung cấp các hàm hệ thống để thực hiện thiết lập một socket.

2. Các loại socket 

Có 2 loại socket được sử dụng rộng rãi là: stream sockets và datagram sockets.

- Stream sockets: Dựa trên giao thức TCP (Tranmission Control Protocol), là giao thức hướng luồng (stream oriented). Việc truyền dữ liệu chỉ

thực hiện giữa 2 tiến trình đã thiết lập kết nối. Giao thức này đảm bảo dữ liệu được truyền đến nơi nhận một cách đáng tin cậy, đúng thứ tự

nhờ vào cơ chế quản lý luồng lưu thông trên mạng và cơ chế chống tắc nghẽn.

- Datagram sockets: Dựa trên giao thức UDP (User Datagram Protocol), là giao thức hướng thông điệp (message oriented). Việc truyền dữ

liệu không yêu cầu có sự thiết lập kết nối giữa tiến quá trình. Ngược lại với giao thức TCP thì dữ liệu được truyền theo giao thức UDP

không được tin cậy, có thế không đúng trình tự và lặp lại. Tuy nhiên vì nó không yêu cầu thiết lập kết nối không phải có những cơ chế phức tạp

nên tốc độ nhanh…ứng dụng cho các ứng dụng truyền dữ liệu nhanh như chat, game…..

3. Minh họa lập trình socket 

Bài viết này minh họa lập trình socket trên linux sử dụng trực tiếp các hàm socket api bằng ngôn ngữ C.
Mô hình lập trình socket TCP giữa 2 tiến trình client và server như sau:

- Các bước thiết lập một socket phía client gồm:

+ Tạo một socket bằng hàm socket()

+ Kết nối socket đến địa chỉ của server bằng hàm connect()

+ Gửi và nhận dữ liệu: Có một số cách khác nhau, đơn giản nhất là sử dụng các hàm read() và write()
+ Đóng kết nối bằng hàm close()

- Các bước thiết lập một socket phía server gồm:

+ Tạo một socket bằng hàm socket()

+ Gắn (bind) socket đến địa chỉ của server sử dụng hàm bind()

Đối với server trên internet địa chỉ bao gồm địa chỉ ip của máy host + số hiệu cổng dịch vụ (port number)

+ Lắng nghe (listen) các kết nối đến từ clients sử dụng hàm listen()

+ Chấp nhận các kết nối sử dụng hàm accept(). Hàm này sẽ dừng (block) cho đến khi nhận được một client kết nối đến.

+ Gửi và nhận dữ liệu với client (hàm read(), write())

+ Đóng kết nối bằng hàm close()

Dưới đây là chương trình minh họa lập trình socket TCP sử dụng socket api và pure C. Mã nguồn tham khảo gồm 2 chương trình:
  • server.c
  • client.c
Biên dịch và chạy 2 chương trình này (trên cùng một máy local host, hoặc 2 máy riêng biệt kết nối mạng)

- Với server:  server portnumber
- Với client:  client server_address portnumber

Client kết nối và gửi một thông điệp đến server, server nhận và trả lời.

Phần tiếp theo giải thích chi tiết mã nguồn

3.1. Chương trình server.c 

/* A simple server in the internet domain using TCP
   The port number is passed as an argument */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>    //Thư viện chứa các cấu trúc cần thiết cho socket
#include <netinet/in.h>    //Thư viện chứa các hằng số, cấu trúc khi sử dụng địa chỉ trên internet
#include <errno.h>

int main(int argc, char *argv[])
{
     int sockfd;  //socket server tạo ra để nghe kết nối 
     int newsockfd; //socket tạo ra khi server chấp nhận một kết nối từ client
     int portno; //So hieu cong dich vu
     
     char sendbuff[256]; //buffer to send data
     char recvbuff[256]; //buffer to read data
     
     struct sockaddr_in serv_addr, client_addr; //Cấu trúc chứa thông tin địa chỉ server, client
   
     int n, len;
     
        
    //So hieu cong dich vu (port number) truyen tu tham so dong lenh 
    if (argc < 2) {
         fprintf(stderr,"ERROR, no port provided\n");
         exit(1);
     }
     portno = atoi(argv[1]); //chuyen thanh so nguyen
             
     //Khoi tao gia tri cho cac vung nho
     memset(&serv_addr, '0', sizeof(serv_addr));
     memset(&client_addr, '0', sizeof(client_addr));
     memset(sendbuff, '0', 256);
     
     //Thiet lap dia chi server
     serv_addr.sin_family = AF_INET;       //default
     serv_addr.sin_addr.s_addr = INADDR_ANY;  //ip server
     serv_addr.sin_port = htons(portno);      //port number
     
     //Tao socket
     sockfd = socket(AF_INET, SOCK_STREAM, 0);
     if (sockfd < 0) 
        error("ERROR opening socket");
     
     //bind socket
     if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
              error("ERROR on binding");
     
     //listening
     listen(sockfd,5);    //Toi da 5 backlog trong hang doi

     len = sizeof(client_addr); //Dung de lay thong tin dia chi client ket noi den

             
     //Server su dung mot vong lap de lien tuc nghe va phuc vu client ket noi den
     while(1){
      printf("Server is listening at port %d\n", portno);
      newsockfd = accept(sockfd, (struct sockaddr *) &client_addr, (socklen_t*)&len);
      if (newsockfd < 0) 
      {
             error("ERROR on accept");
             continue;
         }
         char s[255]; //Chua thong tin dia chi client ket noi den
         inet_ntop(client_addr.sin_family,(struct sockaddr *)&client_addr,s, sizeof s);
         printf("server: got connection from %s\n", s);
                
        memset(recvbuff, 0, 256);
      //read data from socket
      n = read(newsockfd,recvbuff,255);    //block den khi co du lieu tu client gui toi
      if (n < 0) error("ERROR reading from socket");
     
         printf("Message from client: %s\n",recvbuff);
     
      //write data via socket
      strcpy(sendbuff, "Server has got message\n");
      n = write(newsockfd,sendbuff,sizeof(sendbuff));
      if (n < 0) error("ERROR writing to socket");
     
      close(newsockfd);    //Dong ket noi cua client
      sleep(1);
     }
         
     close(sockfd);
     return 0; 
}
3.2. Chương trình client.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 
#include <arpa/inet.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int sockfd, portno, n;
    struct sockaddr_in serv_addr; //Cau truc chua dia chi server ma client can biet de ket noi toi

    char sendbuff[256];
    char recvbuff[256];

    //Client nhan tham so hostname va port tu dong lenh
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }
    portno = atoi(argv[2]); //Chuyen cong dich vu thanh so nguyen
   
   //Tao socket
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
      
    
    memset(&serv_addr, '0', sizeof(serv_addr));

    //Thiet lap dia chi cua server de ket noi den
    serv_addr.sin_family = AF_INET;        //Mac dinh
    serv_addr.sin_port = htons(portno);    //Cong dich vu
   
    //Dia chi ip/domain may chu
    if(inet_pton(AF_INET, argv[1], &serv_addr.sin_addr)<=0)
    {
        printf("\n inet_pton error occured\n");
        return 1;
    }

    //Goi ham connect de thuc hien mot ket noi den server
    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
    {
       printf("\n Error : Connect Failed \n");
       return 1;
    }
        
    printf("Please enter the message: ");
    
    memset(sendbuff, 0, 256); //Khoi tao buffer
    fgets(sendbuff,255,stdin); //Chua thong diep doc tu ban phim 
    
    //Gui du lieu den server bang cach ghi ra socket vua thiet lap
    n = write(sockfd,sendbuff,strlen(sendbuff));
    if (n < 0) 
         error("ERROR writing to socket");
    
    //Nhan du lieu tu server
    memset(recvbuff, 0, 256);
    n = read(sockfd,recvbuff,255);
    if (n < 0) 
         error("ERROR reading from socket");
    printf("%s\n",recvbuff);
   
    close(sockfd); //Dong socket 
    return 0;
}
0 Comments
G+ Comments
Comments

0 comments:

Post a Comment

 
Top

Nhận xét mới đăng tải!

Loading…
X