Lập trình socket, giao tiếp client và server bằng ngôn ngữ C (với giao thức TCP)
Bài đăng này đã không được cập nhật trong 6 năm
Lập trình mạng là gì?
Có bao giờ bạn thắc mắc những chương trình bạn viết ra hoạt động, giao tiếp thế nào trong mạng máy tính chưa? Hay dễ hiểu là làm cách nào để server của bạn có thể nói chuyện được với client?
Lập trình mạng là một trong những nhiệm vụ căn bản để phát triển các ứng dụng. Một chương trình mạng được viết ra để các chương trình trên các máy tính khác nhau có thể truyền tin với nhau một cách hiệu quả và an toàn cho dù chúng được cài đặt trên mạng LAN, WAN hay mạng toàn cầu Internet, đây là điều căn bản đối với sự thành công của nhiều hệ thống.
Hãy cùng mình nghịc thử để viết 1 chương trình socket giao tiếp client và server đơn giản nhất!
Giới thiệu về Socket
SocKet là một giao diện lập trình (API – Application Program Interface) ứng dụng mạng thông qua giao diện này có thể lập trình điều khiển việc truyền thông giữa 2 máy sử dụng các giao thức mức thấp như TCP,UDP… , Có thể tưởng tượng nó như một thiết bị truyền thông 2 chiều tương tự như tệp tin, chúng ta gửi/nhận dữ liệu giữa 2 máy, tương tự như việc đọc ghi trên tệp tin.
Với mô hình khách chủ TCP
Bây giờ chúng ta sẽ bắt tay tìm hiểu cách làm và thực hành
Viết chương trình phía server
Các bước để tạo lên 1 chương trình phía server:
- Tạo socket với hàm
socket (int family, int type, int protocol)
các tham số trong đó theo thứ tự là họ giao thức, kiểu socket, kiểu giao thức. - Gán địa chỉ cho socket
bind (int sockfd, const struct sockaddr *sockaddr, socklen_t addrlen)
các tham số lần lượt là mô tả socket vừa tạo, con trỏ chỏ đến địa chỉ socket, độ lớn địa chỉ - Chỉ định socket lắng nghe kết nối
listen (int sockfd, int backlog)
trong đó sockfd là mô tả socket vừa tạo, backlog là số lượng tối đa các kết nối đang chờ - Chờ/chấp nhận kết nối
accept (int sockfd, struct sockaddr *cliaddr, socklen_t *addrlen)
lần lượt có các tham số là mô tả socket vừa tạo, con trỏ tới cấu trúc địa chỉ socket của tiến trình kết nối đến, độ lớn cấu trúc địa chỉ - Thiết lập kết nối với máy chủ TCP
connect (int sockfd, const struct sockaddr *servaddr, socklen_t addrlen)
Viết chương trình phía client
Các bước để tạo lên 1 chương trình phía client
- Tạo socket với hàm
socket (int family, int type, int protocol)
các tham số trong đó theo thứ tự là họ giao thức, kiểu socket, kiểu giao thức. - Connect tới địa chỉ server với hàm
connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)
- Đọc dữ liệu từ server và ghi vào biến buffer
read( sock , buffer, 1024)
Sau đây mình sẽ đi vào thực hành với 1 requirement đơn giản là:
Mô tả chương trình:
- server mở công kết nối 8080
- client nhập địa chỉ ip để kết nối với server qua cổng 8080
- server hiển thị địa chỉ ip và cổng của client,
- người dùng nhập chuỗi kí tự bất kì từ bàn phím
- client đọc chuỗi kí tự và gửi cho server
- server nhận tin nhắn từ client và trả về tin nhắn nhận được đã viết hoa các kí tự.
- client hiển thị thông báo từ server
- lặp đến khi client nhập”bye” thì đóng kết nối.
Code phía server
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <ctype.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char mess_from_client[225];
char buffer[1024] = {0};
char *hello = "Hello from server";
int continu = 1;
//tao socket
// tao file mo ta soket
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
//gan dia chi cho socket
// gan cong port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT ); //gan cong la 8080
// bind
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
//listen, chi dinh socket lang nghe ket noi
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
//accept, chap nhan ket noi
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
while(continu == 1){
char str_cli_ip[INET_ADDRSTRLEN];
struct sockaddr_in* ip_client = (struct sockaddr_in*)&address;
inet_ntop(AF_INET, &ip_client->sin_addr, str_cli_ip, INET_ADDRSTRLEN);
printf("ipclient: %s\n", str_cli_ip );
char str_cli_port[INET_ADDRSTRLEN];
printf("port: %d\n", ntohs(ip_client->sin_port));
printf("Tin nhan ban nhan dc tu client: \n");
//read, doc du lieu gan vao bien valread tra ve so byte ma no doc duoc
valread = read( new_socket, buffer, 1024);
//viet hoa
ToUp(buffer);
//gan bien hello tra ve cho client la buffer da viet hoa
hello = &buffer;
printf("%s\n",buffer );
send(new_socket, hello, strlen(hello), 0 );
}
close(new_socket);
return 0;
}
void ToUp( char *p )
{
while( *p )
{
*p=toupper( *p );
p++;
}
}
Code phía client
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 8080
int main(int argc, char const *argv[])
{
struct sockaddr_in address;
int sock = 0, valread;
struct sockaddr_in serv_addr;
char *hello = "Hello from client";
char buffer[1024] = {0};
char add[225];
int continu = 1;
printf("Nhap dia chi server\n");
gets(add);
//tao socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("\n Socket creation error \n");
return -1;
}
memset(&serv_addr, '0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
// Convert IPv4 and IPv6 addresses from text to binary form
if(inet_pton(AF_INET, add, &serv_addr.sin_addr) <= 0)
{
printf("\nInvalid address/ Address not supported \n");
return -1;
}
// connect
if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("\nConnection Failed \n");
return -1;
}
while(continu == 1){
char mess_from_client[225];
printf("Nhap noi dung tin nhan gui den server\n");
gets(mess_from_client);
fflush(stdin);
hello = &mess_from_client;
printf("Tin nhan ban nhan dc tu server: \n");
send(sock , hello , strlen(hello) , 0 );
// printf("Hello message sent\n");
valread = read( sock , buffer, 1024);
printf("%s\n",buffer );
if (strcmp(mess_from_client, "bye") == 0)
{
continu = 0;
}
fflush(stdin);
}
close(sock);
return 0;
}
Sau khi build và run mình sẽ được thành quả như sau
Đó là demo về 1 chương trình socket sử dụng ngôn ngữ C đơn giản nhất để tìm hiểu về lập trình mạng, cảm ơn bạn đã đọc nhé.
All rights reserved