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

    Lập trình Winsock trong C# | Winsock programing with C#

    Hôm nay sẽ không phải là chủ đề về Graphics nữa. ZC sẽ mở ra một chủ đề mới đó là về lập trình mạng (đây cũng là chủ đề mà ZC đã hứa sẽ viết cho nhóm Software của huynguyen mà tới hôm nay mới có thời gian rãnh để làm).

    Hiện nay thì môi trường mạng đang phát triển rất nhanh và gần như sự trao đổi dữ liệu giữa các máy tính đang trở nên rất cần thiết.

    Có khá nhiều giải pháp lập trình để làm việc với môi trường mạng như Remote, hay WebServices nhưng Winsock vẫn là những lý thuyết cơ bản nhất.

    Điều duy nhất mà ZC mong muốn đó là sẽ hỗ trợ cho mọi người.
    Mình sẽ cập nhật bài viết này sớm.

  2. #2
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    I. Dữ liệu truyền tải

    Đầu tiên mình sẽ nói sơ qua về vấn đề dữ liệu được truyền tải trên môi trường mạng.

    Dữ liệu ở cấp độ thấp nhất là bit. Cao hơn là byte và còn vài cấp cao hơn nữa. Nhưng byte được xem là chuẩn đề truyền dữ liệu. Do vậy trước khi chúng ta gửi hay nhận bất cứ dữ liệu gì thì bắc buộc ta phải đưa dữ liệu của đối tượng đó về đơn vị byte.

    C# khác với C++ ở nhiều điểm. Và điểm khác rõ nhất là tất cả các kiểu dữ liệu của C# đều là đối tượng (object) Trong khi dữ liệu của C++ là các vùng nhớ trên bộ nhớ.

    Do đó ở C# bạn không thể ép kiểu từ string thành byte như C++ chuyển WCHAR* thành char*.

    Và chúng ta sẽ làm quen cách chuyển đổi này trên C#.

    Hiện nay chúng ta có 3 bảng mã chính, ngoài ra còn nhiều nữa nhưng ít được sử dụng:


    ASCII
    - Bảng mã ASCII thì mỗi ký tự là 1 byte.

    UTF8
    - Bảng mã UTF8 thì trong 1 chuỗi string không hẵn các ký tự là 1 byte, có khi nó tới 2,3 byte tùy thuộc vào ký tự đó.
    - Tức là những ký tự có trong mã ASCII thì nó chiếm 1 byte. Còn các ký tự đặc biệt như chữ 'ô' 'ê'... thì biểu diễn tới 2 hay 3 bytes tùy thuộc vào bảng mã.

    UTF16 hay Unicode
    - Bảng mã UTF16 thì sang hơn 1 chút. Các ký tự chiếm đều 2 bytes nên nó có thể biểu diễn mọi ngôn ngữ trên thế giới.
    - UTF16 có 2 loại là UTF16-LE (Unicode chuẩn) và UTF16-BE.
    - UTF16-BE (Big Endian) khác so với UTF16 (Little Endian) ở chỗ hoán đổi vị trí bytes trên 1 ký tự. Ví dụ :ký tự ở UTF16-LE có giá trị là 0xAABB thì UTF16-BE ký tự đó sẽ là là 0xBBAA</font>

    + UTF16 được sử dụng khá rộng rãi.
    + UTF8 thì lại được sử dụng chính trên các giao thức như HTTP, SOAP vì nó tiết kiệm được dữ liệu.
    + ASCII khá cổ nhưng vẫn được sử dụng.

    Trong C# kiểu char chiếm 2 bytes. Kiểu byte chiếm 1 byte. string là đối tượng của mảng char[] nên nó thể hiện chuỗi Unicode.
    Vậy còn các kiểu như float, int32,... làm cách nào để chuyển thành byte[], giải pháp đặt ra là phải parse ( ToString() ) các kiểu này thành string rồi chuyển thành byte.

    <font color="DarkRed">1. Chuyển dữ liệu thành BYTE


    UTF16 thành ACSII

    Mã:
    string examString = "Đây là chuỗi UTF16!!!";byte[] ascii= ASCIIEncoding.ASCII.GetBytes(examString);
    UTF16 thành UTF8

    Mã:
    string examString = "Đây là chuỗi UTF16!!!";byte[] utf8= ASCIIEncoding.UTF8.GetBytes(examString);
    2. Chuyển BYTE thành các dữ liệu tương ứng

    ASCII thành Unicode


    Mã:
    string examString = "Đây là chuỗi UTF16!!!";byte[] ascii= ASCIIEncoding.ASCII.GetBytes(examString);// ASCII -> UNICODEstring result = Encoding.ASCII.GetString(utf8);
    UTF8 thành Unicode


    Mã:
    string examString = "Đây là chuỗi UTF16!!!";byte[] utf8= ASCIIEncoding.UTF8.GetBytes(examString);// UTF8 -> UNICODEstring result = Encoding.UTF8.GetString(utf8);

  3. #3
    II. Address

    1. Địa chỉ IP</font>

    Khi bạn gửi 1 bức thư, 1 điều cần thiết nhất là bạn phải có địa chỉ nơi nhận. Và trên Internet cũng vậy, mỗi host truy cập lên mạng thì sẽ có 1 IP để xác định chính nó.

    Ip có 2 loại là V4 (4bytes) và V6 (6bytes).

    Ta sẽ xét cấu trúc V4 vì nó đang được sử dụng.

    1 địa chỉ IP thì nó chứa 2 thông tin:
    + NetID: Chỉ ra "đường mạng" (dựa vào đường mạng người ta lại phân lớp: A, B, C).
    + HostID: Là ID của máy tính trên đường mạng đó.

    2 Host chỉ có thể trao đổi trực tiếp dữ liệu khi 2 host đó cùng trên 1 đường mạng. Còn nếu khác đường mạng thì nó phải đi qua các thiết bị chuyên dụng gọi là Router. ASDL Modem cũng chính là 1 router nhưng nó không phải là Router chuyên dụng. Nó chỉ có 1 chức năng của router chính là NAT (Network Address Translate - Chuyển đổi đường mạng).


    Nếu muốn nói sâu về IP thì có thể mất cả 1 tut nữa. Mình sẽ nôn na như thế này.

    Trích dẫn Gửi bởi ZCoder87
    Chúng ta tưởng tượng TP HCM như là mạng Internet. "Đường mạng" chính là 1 con đường nào đó trong TP. Như vậy Quận có thể xem như là "lớp của IP (IP chia thành lớp 3 lớp A,B,C còn 2 lớp không sử dụng)".

    Bạn là một packet (gói tin) đang muốn đi từ điểm A tới điểm B trên thành phố?

    Vậy:
    - Nếu như điểm B và A cùng 1 con đường thì bạn có thể đi thẳng được. (Đây là trường hợp các host trong cùng 1 mạng LAN)

    - Còn nếu khác đường mạng (có thể LAN hoặc WAN). Thì bạn sẽ phải qua các ngã 3, 4.... Chúng ta xem điểm này như là các Router, tại đó nó sẽ có bảng chỉ dẫn để chúng ta đi đúng đường. Và bạn sẽ phải qua rất nhiều Router mới có thể đến được điểm B.

    Và đó cũng là quy luật của Internet.
    Chúng ta có thể kiểm chứng 1 ví dụ để biết được đường đi qua các router.
    - Vào Start -> Run -> cmd (enter)
    - Sau đó gõ lệnh "tracert google.com.vn"

    Bạn có thể xem thêm thông tin về IP ở Lập Trình Mạng Với Thư Viện Winsock trên VC++

    a. Đối tượng IPAddress

    <font color="Red">Namespace: using System.Net;


    1 IP sẽ chiếm hết 4 bytes. Do đó có thể xem như kiểu long hoặc byte[4].

    Để thiết lập 1 địa chỉ IP chúng ta có thể dùng cách sau:

    Từ 1 mảng bytes[4]

    Mã:
    // Thiet lap IP 203.162.4.190byte []dnsIP = {203,162,4,190};IPAddress ip = new IPAddress(dnsIP); Console.WriteLine(ip);
    Hoặc từ 1 string:

    Mã:
    byte[] ipFromString(string ipString){    string[] byteString = ipString.Split(new char[] { '.' });    byte[] adr = new byte[4];     adr[0] = byte.Parse(byteString[0]);    adr[1] = byte.Parse(byteString[1]);    adr[2] = byte.Parse(byteString[2]);    adr[3] = byte.Parse(byteString[3]);     return adr;}
    và sau đó thì:


    Mã:
    string ipString = "210.245.0.11"; IPAddress ip = new IPAddress(ipFromString(ipString));Console.WriteLine(ip);

  4. #4
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Đối tượng IPEndpoint

    Đây là đối tượng mà nó bao gồm 2 thông tin chính là IP Host và cả Port.


    Mã:
    try{          // Lấy danh sách IP congdongcviet.com          IPAddress[] ipServer = Dns.GetHostAddresses("congdongcviet.com");                    // Kết nối port 80          IPEndPoint server = new IPEndPoint(ipServer[0], 80);               }catch (Exception){          Console.WriteLine("DNS Error");}

  5. #5
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Hôm nay mình sẽ đi vào phần chính...

    I. CHƯƠNG TRÌNH CLIENT

    1. TCP Client

    a. Kết nối
    .NET có hỗ trợ sẵn một đối tượng dành cho Client. Đó là lớp đối tượng TCPClient

    Ví dụ như kết nối tới port 80 của Server congdongcviet.com:

    Mã:
    IPAddress[] ipServer = Dns.GetHostAddresses("congdongcviet.com");IPEndPoint server = new IPEndPoint(ipServer[0], 80); // Ket noi toi serverTcpClient client = new TcpClient();client.Connect(server);
    Yêu cầu duy nhất để khởi tạo TCPClient là địa chỉ host và port host. Nó đã được định nghĩa ở IPEndPoint

    b. Truyền và nhận dữ liệu

    Bản chất của truyền và nhận dữ liệu cũng như ghi và đọc 1 stream (NetworkStream)


    Mã:
    NetworkStream htmlProtocol = client.GetStream();                // Thong tin headerstring header = String.Format("GET / HTTP/1.1
    Host: {0}
    User-Agent:{1}
    
    ",         "congdongcviet.com",         "ZClient");byte[] byteHeader = ASCIIEncoding.ASCII.GetBytes(header);                // {*} Gui du lieu cho ServerhtmlProtocol.Write(byteHeader,0,byteHeader.Length);
    Đoạn code trên sẽ gửi 1 đoạn message như sau tới server:


    Mã:
    GET / HTTP/1.1
    
    Host: congdongcviet.com 
    
    User-Agent: ZClient
    Và cũng chính là là giao thức HTTP.

    c. Nhận dữ liệu

    NetworkStream có 2 cơ chế nhận dữ liệu rất cơ bản là:
    - ReadByte() Nhận từng byte.
    - Read() Nhận một lượng bytes nào đó.

    Cách tốt nhất là mình ví dụ code, mình đã note code rồi:

    Dưới đây là cách nhận từng byte một.


    Mã:
    static void Connect(string domain){      try      {            // Phan giai ten mien: domain -> ip            IPAddress[] ipServer = Dns.GetHostAddresses(domain);            IPEndPoint server = new IPEndPoint(ipServer[0], 80);             // Ket noi toi server            TcpClient client = new TcpClient();            client.Connect(server);             NetworkStream htmlProtocol = client.GetStream();             // Thong tin header            string header = String.Format("                  GET / HTTP/1.1
                      Host: {0}\                  nUser-Agent:{1}
    
    ",                         domain,                        "ZClient");            byte[] byteHeader = ASCIIEncoding.ASCII.GetBytes(header);              // {*} Gui du lieu cho Server            htmlProtocol.Write(byteHeader, 0, byteHeader.Length);             Console.WriteLine("Header from {0}", domain);             // {*} Nhan du lieu tu server            int nEndHeader = 0;            while (nEndHeader != 4)            {                  char b = (char)htmlProtocol.ReadByte();                   Console.Write(b);                   // Khi nhan chuoi ky tu 
    
     thi het Header                  if (b == '
    ' || b == '
    ')                        nEndHeader++;                  else                        nEndHeader = 0;            }                  }      catch (Exception e)      {            Console.WriteLine(e.Message);      }}
    Và đây là kết quả response theo giao thức http của các webserver. Nó có thể cho ta biết server tên gì và chạy hdh gì.


    Mã:
    Connect("google.com");
     HTTP/1.1 301 Moved Permanently
    Location: http://www.google.com/
    Content-Type: text/html; charset=UTF-8
    Date: Tue, 18 Nov 2008 07:19:23 GMT
    Expires: Thu, 18 Dec 2008 07:19:23 GMT
    Cache-Control: public, max-age=2592000
    Server: gws
    Content-Length: 219
    Của congdongcviet.com nhà ta:

    Mã:
    Connect("congdongcviet.com");
     HTTP/1.1 200 OK
    Content-Length: 14121
    Content-Type: text/html
    Content-Location: http://congdongcviet.com/index.htm
    Last-Modified: Thu, 06 Nov 2008 04:32:07 GMT
    Accept-Ranges: bytes
    ETag: "a4ba69a0c83fc91:197e4"
    Server: Microsoft-IIS/6.0
    X-Powered-By: ASP.NET
    Date: Tue, 18 Nov 2008 07:20:04 GMT

    Mã:
    Connect("forums.congdongcviet.com");
     HTTP/1.1 200 OK
    Date: Tue, 18 Nov 2008 07:25:56 GMT
    Server: Apache
    X-Powered-By: PHP/5.2.6
    Cache-Control: private
    Pragma: private
    Set-Cookie: bbsessionhash=e72b5bfe86b49410e3492d3b26bcb904; path=/; HttpOnly
    Set-Cookie: bblastvisit=1226993156; expires=Wed, 18-Nov-2009 07:25:56 GMT; path=/
    Set-Cookie: bblastactivity=0; expires=Wed, 18-Nov-2009 07:25:56 GMT; path=/
    Transfer-Encoding: chunked
    Content-Type: text/html; charset=utf-8
    Còn tiếp...

  6. #6
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    cho mình hỏi.nếu mình tăng nEndHeader != 4 lên 100 lần thì đọc được cả body.nhưng mà khi đọc hết nó lại lấy gia trị nuLL bây giờ phải làm sao để đọc hết thì nó thôi!

  7. #7
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    nEndHeader == 4 có nghĩa là khi nó gặp dấu hiệu kết thúc Header là "2 lần xuống hàng" (

    hay là



    )

    Còn phần Body thì mình chưa load. Định tiếp viết phần đó tiếp theo nhưng chưa có thời gian rãnh. Để dọc được body thì bạn có thể đọc 1 lúc 512 bytes chứ ko phải 1 byte nữa, Và read nhiều lần như thế để lấy hết nội dung body website, nếu hàm read trả về giá trị < 512 có nghĩa là kết thúc body.

    Còn việc bạn tăng lên 100 có thể chương trình sẽ gặp exception

  8. #8
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Trích dẫn Gửi bởi ZCoder87
    [size=3][COLOR="Sienna"][b]
    Hoặc từ 1 string:

    Mã:
    byte[] ipFromString(string ipString){    string[] byteString = ipString.Split(new char[] { '.' });    byte[] adr = new byte[4];     adr[0] = byte.Parse(byteString[0]);    adr[1] = byte.Parse(byteString[1]);    adr[2] = byte.Parse(byteString[2]);    adr[3] = byte.Parse(byteString[3]);     return adr;}
    và sau đó thì:


    Mã:
    string ipString = "210.245.0.11"; IPAddress ip = new IPAddress(ipFromString(ipString));Console.WriteLine(ip);
    Dùng vậy dễ hơn nè [IMG]images/smilies/biggrin.png[/IMG]

    Mã:
    IPAddress ip = IPAddress.Parse(hostname)

  9. #9
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    Mình đã thử viết 1 chương trình chat được qua Lan, nhưng qua Wan thì không kết nối 2 máy đươc, lên mạng tìm hiểu thì phải cấu hình port forwarding trong router. Mình có một thắc mắc là down torrent cũng có kết nối trực tiếp giữa 2 máy, mà có cần chỉnh port trong router đâu?!?

  10. #10
    Ngày tham gia
    Sep 2015
    Bài viết
    0
    mình cũng làm bài tập lớn chát trong mạnglan, minh đã chát được nhiều máy client với với một máy sever, nhưng hiện tại mình muốn chát gữu các máy client với nhau thì làm sao, mình làm như yahooo có ôn không?
    vấn đề nữa là mình muốn truyền file trong mạng lan thì truyển coa khác j không so với truyền file text có khác nhau j không
    vd mình muốn truyền file wmv chẳng hạn

 

 
Trang 1 của 2 12 CuốiCuối

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
  •