Chào mừng đến với Diễn đàn lập trình - Cộng đồng lập trình.
Kết quả 1 đến 6 của 6
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Lập trình mạng trong Visual C++ 6, xây dựng ứng dụng client server đơn giản

    Bài này sẽ hướng dẫn các bạn làm 1 ứng dụng client-server cơ bản.

    I. Socket
    Cơ bản nhất khi lập trình mạng chính là khái niệm socket.
    Socket nghĩa là 1 cái "ổ cắm". Có thể tưởng tượng thế này (xin lỗi vì vẽ hơi xấu ^_^):


    Tất nhiên đường dây ở trên chỉ là đường dây ảo.
    Toàn bộ quá trình trao đổi sẽ diễn ra qua các socket.
    1 socket khi được tạo có thể có các trạng thái: bind (gắn vào 1 cổng), listen (chờ kết nối), connected (đã kết nối với socket khác).
    Socket khi chỉ bind vào 1 cổng có thể nhận các tin được gửi từ mạng đến cổng đó.

    Để tạo 1 socket ta dùng hàm sau:

    SOCKET sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);

    - Tham số thứ nhất là loại kết nối, thường là AF_INET.
    - Tham số thứ 2 là kiểu kết nối, SOCK_STREAM cho TCP, SOCK_DGRAM cho UDP và các kiểu connectionless (không cần kết nối).
    - Tham số thứ 3 là giao thức, IPPROTO_TCP chỉ dùng cho SOCK_STREAM.
    (Để biết thêm về các loại giao thức và kết nối, vào MSDN, ở đây chỉ giải thích qua).

    *Chú ý: Ta cần thêm thư viện ws2_32.lib và include file winsock2.h. Để dùng các hàm winsock, trước tiên cần làm thế này:


    Mã:
    WSADATA wsadata;WSAStartup (&wsadata, MAKEWORD (2, 2));
    Hàm API WSAStartup sẽ khởi tạo winsock cho ứng dung với phiên bản yêu cầu, ở đây là 2.2, các thống số về winsock sẽ tra lại trong wsadata


    II. Khởi tạo phía server

    Các bước thực hiện trên server:

    B1: Tạo socket TCP.



    Mã:
    SOCKET ListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
    <font size="3">B2: Bind (gắn) socket này vào 1 cổng, client sẽ nối đến server qua cổng này.


    Ở đây dùng cổng 4444:

    Mã:
    sockaddr_in name;name.sin_family = AF_INET;name.sin_addr.s_addr = inet_addr("127.0.0.1");name.sin_port = htons(4444);bind (ListenSock, (sockaddr*) &name, sizeof (name));
    127.0.0.1 là địa chỉ IP quy định đặt cho localhost, cũng có thể dùng địa chỉ ip trong mạng lan như 10.0.0.1....
    Hàm inet_addr ("x.x.x.x") chuyển chuỗi địa chỉ ip thành 1 số 4 byte. Và ngược lại là hàm inet_ntoa (long x), chuyển địa chỉ dạng số 4 byte sang chuổi.

    B3: Cho socket này listen, chờ kết nối.

    Mã:
    listen (ListenSock, 1);
    Tham số thứ 2 của hàm API listen là backlog, em cũng ko hiểu rõ, nhưng thường được để là 1. Hàm listen là 1 vòng lặp, sẽ kết thúc nếu có 1 yêu cầu kết nối.

    B4: Có yêu cầu kết nối. Nếu đồng ý, sẽ có 1 socket khác được tạo và trao đổi với client qua socket này, còn socket để listen sẽ đóng lại và có thể nghe trên 1 cổng khác để tiếp nhận 1 client khác.


    Mã:
    sockaddr_in clientaddr;SOCKET client = accept (ListenSock, (sockaddr*) &clientaddr, sizeof (clientaddr));closesocket (ListenSock);
    Nếu muốn, lặp lại quá trình trên để phục vụ 1 client khác:


    Mã:
    ListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);.....
    Tham số thứ hai trong accept sẽ nhận lại thông tin về client yêu cầu kết nối như địa chỉ ip của client... và bạn có thể ngắt kết nối với client này nếu ko muốn và lặp lại quá trình nghe trên ListenSocket.


    Mã:
    closesocket (client);
    II. Khởi tạo phía client

    B1: Tạo socket TCP


    Mã:
    SOCKET sock = socket (AF_iNET, SOCK_STREAM, IPPROTO_TCP);
    B2: Kết nối đên server (kết nối đên cái socket đang listen của server)


    Mã:
    sockaddr_in name;name.sin_family = AF_INET;name.sin_addr.s_addr = inet_addr("127.0.0.1");name.sin_port = htons(4444);connect (sock, (sockađr*) &name, sizeof (name));
    127.0.0.1 là địa chỉ máy server, vì thử nghiệm sever và client trên cùng 1 máy nên dùng cùng 1 địa chỉ ip.
    4444 là port (cổng) mà socket phía server được bind vào.
    Có thể lấy giá trị lỗi tra về qua hàm WSAGetLastError.

    <font size="5">IV. Gửi và nhận dữ liệu


    Để gửi dữ liệu, ta dùng hàm send:

    send (SOCKET s, const char* buf, int len, int flags);

    s ở phía server trong VD trên là client. ở client là sock.
    buf là thông tin cần gửi. len là kích thước của buf (byte), flag cứ để là 0 cũng được.

    Để nhận dữ liệu ta dùng hàm recv.
    recv (SOCKET s, char* buf, int len, int flags);

    s ở recv cũng giống như send.
    buf là bộ đệm để chứa dữ liệu, len là kích thước tối đa của buf. flags có thể có giá trị MSG_PEEK để copy dữ liệu vào buf, còn bộ đệm của socket vẫn giữ nguyên, nếu ko có giá trị này, bộ đệm của socket sẽ được xóa sau khi copy vào buf.
    Giá trị trả về của recv có thể là:
    0: kết nối đã được ngắt bởi phía server.
    < 0: Đã có lỗi xảy ra. Lấy lỗi bằng WSAGetLastError.
    > 0: kích thước của dữ liệu gửi đến.
    recv là 1 vòng lặp kết thúc đến khi nào có dữ liệu đến hay kết nối bị ngắt, thường dùng 1 thread riêng để xử lí.


    Đây là bài đầu tiên em viết nên có nhiều sai sót, mong mọi người góp ý sửa chữa.</font></font>

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Mình muốn bổ xung một số điều
    1. Do server phải đáp ứng được khi có nhiều client kết nối đến nên việc lắng nghe kết nối của server được đặt trong một vòng lặp vô hạn, bất cứ khi nào thấy có một kết nối thì sẽ tạo ra một luồng riêng để xử lí kết nối này với client. Đồng thời bên server phải quản lý tất cả các kết nối này (cho vào một mảng chẳng hạn) để phục vụ khi các client muốn trao đổi với nhau

    2. Bên phía client cũng tạo ra một luồng riêng cũng đặt trong vòng lặp vô hạn để trao đổi với server. Chú ý là vòng lặp vô hạn ở 2 phía khác hoàn toàn về mục đích [IMG]images/smilies/biggrin.png[/IMG]

    Buồn ngủ quá, viết vậy chả biết có gì sai sót không [IMG]images/smilies/biggrin.png[/IMG]

  3. #3
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Máy khác mà bạn nói nằm cùng mạng LAN hay là WAN? Nếu là WAN thì phải mở cổng modem ở phía server. Nếu mà bạn cài trên máy bạn mà chạy tốt thì mình nghĩ là do bạn chưa mở cổng cho modem bên server.

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    mình có làm 1 ứng dụng gửi và nhận mail theo các bạn hướng dẫn(chỉ viết chương trình gửi và nhận mail thôi, còn server thì kiếm 1 con free,ví dụ như con: ArGoSoftMailserver).khi cài con server này trên máy mình thì chạy rất ngon,nhưng khi cài sang máy khác thì mình ko kết nối đến đc.xin hỏi có cách nào khắc phục ko?mình có hỏi qua 1 số bạn bè, thấy bảo là khi viết ctrinh thì fai làm đa luồng, mình lại ko rõ về vđề này,các bạn có thể giúp m ko

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    ah cho mình hỏi thêm chút nữa là, nếu khắc phục được như vậy thì ứng dụng của mình có thể gửi và nhận mail từ yahoo,gmail đc chứ

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Hàm accept mà bạn nêu ở trên không chính xác không đúng cấu trúc
    tham số cuối của hàm accept phải là
    SOCKADDR_IN clientAddr;
    int clientAddrlen=sizeof(clientAddr);
    tham số cuối phải là &clientAddrlen
    thế mới đúng
    và cái accept thì chỉ phía Server của giao thức TCP mới cần thôi
    mà các bạn cũng có viết cho client và Server theo TCP có thể gửi nhận đồng thời và Server có thể tiếp nhận nhiều client đến!

 

 

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •