LẬP TRÌNH SOCKET VỚI TCP/UDP

 

Một số khái niệm cần biết


-Socket là gì?
“Socket là một cổng logic mà một chương trình sử dụng để kết nối với một chương trình khác chạy trên một máy tính khác trên Internet. Chương trình mạng có thể sử dụng nhiều Socket cùng một lúc, nhờ đó nhiều chương trình có thể sử dụng Internet cùng một lúc.”
- Ứng dụng Client – Server là gì
Trước tới giờ, các bạn lập trình với mục đích là tạo ra được một ứng dụng. Nhưng ứng dụng đó chỉ hoạt động độc lập 1 mình riêng lẽ.
Mục tiêu lập trình mạng sẽ đưa ra những ứng dụng dạng Client – Server. Tức là sẽ có 2 loại ứng dụng chính đó là Client và Server.
Quy trình hoạt động của ứng dụng Server – Client như sau:
- Server có nhiệm vụ của là lắng nghe, chờ đợi kết nối từ Client trên địa chỉ IP của mình với PORT được quy định sẵn. Khi client gởi dữ liệu tới Server thì nó phải giải quyết một công việc là nhận dữ liệu đó -> xử lý -> trả kết quả lại cho Client.
- Client là ứng dụng được phục vụ, nó chỉ gởi truy vấn và chờ đợi kết quả từ Server.
-TCP là một trong các giao thức cốt lõi của bộ giao thức TCP/IP. Giao thức TCP hoạt động ở tầng thứ 4 (tầng giao vận) trong 7 lớp OSI. TCP là tầng trung gian giữa giao thức IP bên dưới và một ứng dụng bên trên. Giao thức này đảm bảo chuyển giao dữ liệu tới nơi nhận một cách đáng tin cậy và đúng thứ tự, nhờ vào cơ chế quản lý luồng lưu thông trên mạng và cơ chế tránh tắt nghẽn mạng.
-UDP là một trong 2 giao thức chính của mô hình TCP/IP để truyền tải dữ liệu. CLIENT – SERVER sử dụng UDP sẽ không bao giờ quan tâm đến về đề dữ liệu có chính xác hay không? Bên gửi cứ gửi và bên nhận cứ nhận, nhận không được thì mặc kệ…

- Người ta sử dụng UDP trong những ứng dụng cần truyền dữ liệu nhanh như CHAT,GAME ONLINE,….

1.Cơ chế gọi hàm trong lập trình Socket


a.TCP


 



Lập trình Socket với TCP


 

 

b.UDP




Lập trình Socket với UDP


2.Thư viện lập trình Winsock


2.1. Khởi động và đóng thư viện


2.1.1. Khởi động Winsock
int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

Các tham số:
- wVersionRequested là phiên bản thư viện mà mình sử dụng. Ở đây sẽ là giá trị 0×0202 có nghĩa là phiên bản 2.2.
- lpWSData là một số thông tin bổ sung sẽ được trả về sau khi gọi khởi tạo Winsock
2.1.2. Đóng thư viện Winsock
WSACleanup (void);

2.2. Window socket


2.2.1. Tạo socket
SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

Các tham số:
      – af: [in] mô tả họ địa chỉ.
      – type: [in] kiểu của socket.
              + SOCK_STREAM: TCP socket
              + SOCK_DGRAM: UDP socket
      -protocol: [in] nghi thức được sử dụng trên socket.
              + SOCK_DGREAM -> protocol là: IPPROTO_UDP
              + SOCK_STREAM -> protocol là: IPPROTO_IP
              +  SOCK_RAW -> protocol có thể là: IPPROTO_RAW hay IPPROTO_ICMP
2.2.2 Hàm lấy tên máy mình:
int gethostname(char* name, int namelen);

2.2.3Hàm lấy thông tin theo tên máy:
struct hostent* FAR gethostbyname(const char* name);

* Các tham số
        • name: [in] tên của máy tính cần phân giải.
* Giá trị trả về
       • Một cấu trúc HOSTENT, nếu thành công
       • NULL, nếu có lỗi
Trong đó hostent đc định nghĩa
typedef struct hostent {
char FAR* h_name; // Tên máy tính
char FAR FAR** h_aliases; // Bí danh máy tính
short h_addrtype; // Kiểu IP (AF_INET)
short h_length; // Kích thước IP
char FAR FAR** h_addr_list; // Danh sách các địa chỉ IP
// 1 host có thể có 1 hoặc nhiều IP
} HOSTENT,

2.2.4 Lấy thông tin khi biết địa chỉ IP
hostent* FAR gethostbyaddr(const char* addr, int len, int type);

Các tham số
       • addr: [in] địa chỉ của máy tính theo thứ tự network-byte.
       • len: [in] chiều dài của chuỗi địa chỉ
       • type: [in] kiểu của địa chỉ, được thiết lập là AF_INET.
* Giá trị trả về
   • Một cấu trúc HOSTENT, nếu thành công
       • NULL, nếu có lỗi

2.3. TCP


2.3.1. Gắn địa chỉ cho socket
int bind( SOCKET s, const struct sockaddr FAR* name, int namelen )

Các tham số
     • s: [in] socket chưa được gắn kết địa chỉ.
     • name: [in] địa chỉ được gán cho socket, một cấu trúc SOCKADDR.
     • namelen: [in] kích thước của giá trị tham số name.
* Giá trị trả về
     • 0, nếu thành công
     • SOCKET_ERROR, nếu có lỗi.
2.3.2. Lắng nghe kết nối
int listen( SOCKET s, int backlog );

* Các tham số
       • s: [in] socket đã được gắn địa chỉ nhưng chưa kết nối.
      • backlog: [in] kích thước tối đa của hàng đợi thiết lập kết nối. Giá trị tối đa được chỉ định bằng hằng số SOMAXCONN.
2.3.3. Chấp nhật thiết lập một kết nối
SOCKET accept( SOCKET s, struct sockaddr FAR* addr, int FAR*  addrlen )

* Các tham số
       • s: [in] socket đang lắng nghe yêu cầu kết nối.
       • addr: [out] địa chỉ của socket ở máy client đang thực hiện kết nối.
       • addrlen: [out] chiều dài thực sự của addr. Phải khởi tạo giá trị ban đầu là kích thước của addr
* Giá trị trả về
      • Một SOCKET để giao tiếp thực sự với client, nếu thành công
      • INVALID_SOCKET, nếu có lỗi
2.3.4. Thiết lập một kết nối
int connect( SOCKET s, const struct sockaddr FAR* name, int namelen )

* Các tham số
     • s: [in] socket chưa kết nối.
     • name: [in] socket cần kết nối đến.
     • namelen: [in] kích thước của name.
* Giá trị trả về
     • 0, nếu thành công
     • SOCKET_ERROR, nếu có lỗi
2.3.5. Gửi dữ liệu
int send( SOCKET s, const char FAR * buf, int len, int flags )

* Các tham số
     • s: [in] socket đã kết nối.
     • buf: [in] vùng đệm chứa dữ liệu cần gửi.
     • len: [in] chiều dài dữ liệu trong buf.
     • flags: [in] chỉ định cách thức truyền dữ liệu, truyền dữ liệu bình thường, thiết lập giá trị 0.
* Giá trị trả về
     • số byte đã gửi đi, nếu thành công
     • SOCKET_ERROR, nếu có lỗi.
2.3.6. Nhận dữ liệu
int recv( SOCKET s, char FAR* buf, int len, int flags )

* Các tham số
     • s: [in] socket đã kết nối.
     • buf: [out] vùng đệm để lưu dữ liệu nhận.
     • len: [in] kích thước vùng đệm buf.
     • flags: [in] chỉ định cách thức nhận dữ liệu, nhận dữ liệu bình thường, thiết lập giá trị 0.
* Giá trị trả về
     • số byte dữ liệu nhận được, nếu thành công
     • SOCKET_ERROR, nếu có lỗi.
2.3.7 Shutdown
int shutdown( SOCKET s, int how )

* Các tham số
      • s: [in] socket cần shutdown.
      • how: [in] chỉ định những loại thao tác nào không thực hiện nữa.
                  o SD_RECEIVE: không cho phép gọi các hàm recv() trên socket.
                 o SD_SEND: không cho phép gọi các hàm send() trên socket.
                 o SD_BOTH: không cho phép gọi cả send() và recv() trên socket.
* Giá trị trả về
      • 0, nếu thành công
     • SOCKET_ERROR, nếu có lỗi
2.3.7 Đóng socket
int closesocket (SOCKET s)

* Các tham số
     • s: [in] socket cần đóng.

3.Chương trình demo


Và sau đây mình sẽ viết ví dụ về chương trình chat giữa 2 máy trong mạng lan ứng dụng Server – Client sử dụng TCP. Các bạn có thể dowload project demo ở đây

Sever:












01#include <stdio.h>










02#include <tchar.h>










03#include "iostream"










04#include <winsock2.h>










05using namespace std;










06#pragma comment (lib,"ws2_32.lib")










07int _tmain(int argc, _TCHAR* argv[])










08{










09    WSADATA SInfo;










10    int iResult = WSAStartup(0x0202,&SInfo);










11    SOCKET NewConnection,socketSever;










12    socketSever =socket(AF_INET,SOCK_STREAM,IPPROTO_IP);










13    if (socketSever!=INVALID_SOCKET)










14    {










15        cout<<"\nKhoi tao socket thanh cong!!!\n";










16    }










17    char DataGui[512];










18    char DataNhan[512];










19    //Thiet lap IP sever










20    sockaddr_in severAddr;










21    severAddr.sin_family=AF_INET;










22    severAddr.sin_port= htons(2000);










23    severAddr.sin_addr.s_addr= INADDR_ANY;










24    //Thiet lap IP client










25    if (iResult==0)










26    {










27        if (bind(socketSever,(sockaddr*)&severAddr,sizeof(severAddr))==0)










28        {










29            int nSize;










30            //Lang nghe










31            if (listen(socketSever,5)==SOCKET_ERROR )










32            {










33                cout<<"\nLang nghe that bai";










34            }










35            else










36                cout<<"Dang lang nghe ket noi...";










37            while(1)










38            {










39                nSize=sizeof(severAddr);










40                NewConnection=accept(socketSever,(sockaddr*)&severAddr,&nSize);










41                if (NewConnection==-1)










42                {










43                    cout<<"\nLoi ket noi tu Client";










44                    continue;










45                }










46                cout<<"\nKet noi thanh cong..!";










47                cout<<"\nNhan ket noi voi Client co IP: "<<inet_ntoa(severAddr.sin_addr);










48                cout<<"\nBAT DAU NOI CHUYEN VOI NHAU";










49                while(1)










50                {










51                    recv(NewConnection,(char*) &DataNhan,sizeof(DataNhan),0);










52                    cout<<"\nClient: "<<DataNhan;










53                    cout<<"\nSever: ";










54                    cin.getline(DataGui,512);










55                    send(NewConnection,(char*) &DataGui,sizeof(DataGui),0);










56                }










57                closesocket(NewConnection);










58            }










59        }










60        else










61            cout<<"\nThiet lap IP va Port cho socket that bai";










62        WSACleanup();










63    }










64    else










65        cout<<"Loi khoi dong Winsock";










66    system("PAUSE");










67}




Client:


 

Post a Comment

Mới hơn Cũ hơn