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.
đượ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.
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…..
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:
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:
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()
+ Đó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()
+ Đó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:
Post a Comment