Lập trình socket trong java ( phần 1 )
White

Thuong Nguyen Van viết ngày 08/12/2017

Lập trình socket trong Java

Lời nói đầu : Theo đúng lộ trình thì mỗi một kì học mình sẽ làm một project ( tự tìm hiểu về một cái gì đó mình nghĩ là hay ). Qua bài viết này mình mong muốn cung cấp cho các bạn cái nhìn tổng quát nhất về lập trình socket trong java hay bao quát hơn chính là i.o data ( vào ra dữ liệu ) trong java cũng như trong các ngôn ngữ khác. Mình luôn tìm cách sao cho các vấn đề được tiếp cận từ góc độ mình nghĩ la đơn giản nhất mà lại sâu sắc thể hiện bản chất vấn đề. Nghĩa là trên các nền tảng khác các ngôn ngữ khác thì lý thuyết này vẫn đúng. Vì vậy mà bài viết này có thể dài.

Nội dung chính

Socket là gì ?
. Computer network và internet ( Định nghĩ đơn giản về giao thức )
. Cốt lõi của một network application ( Kiến trúc của một app network và giao thức quan trọng của suface web )
Lập trình Socket trong java.
. Stream trong java ( Gom gọn tất cả các lý thuyết I.o trong java bằng 2 khái niệm: luong cơ bản và bộ lọc )
. Chương trình sử dụng tcp socket

Socket là gì ?

Computer network và internet

internet

-Sau khi phát minh ra máy tính người ta đã nghĩa ra các kết nối lại với nhau để trao đổi dữ liệu. Đó là nguyên nhân ra đời của mạng máy tính ( là mạng của các máy tính ). Nghĩa là chỉ có các máy tính kết nối vs nhau và nó gọi là máy chủ ( server )
-Sau này có nhiều thiết bị kết nối vào mạng máy tính hơn để truyền dữ liệu như laptop, điện thoại, tivi, ô tô… Mạng máy tính thật sự là một thuật ngữ cũ . Với internet thì tất cả các thiết bị kết nối vào gọi là host hoặc end system. Tất cả các dịch vụ do internet cung cấp đều là do việc trao đổi dữ liệu giữa các thiết bị tham gia kết nối vào internet. Bạn hoàn toàn có thể biến máy tính của bạn thành một máy chủ giống google để các thiết bị khách kết nối đến nhưng máy tính của bạn có thể không đủ mạnh mẽ để làm điều đó.
-Mấu chốt của việc xây dựng mạng máy tính hay hay internet là xây dựng dựng những quy tắc mà từ đó các thiết bị có thể kết nối được với nhau và trao đôi dữ liệu hay đó chính là protocol: Protocol là khái niệm quan trọng nhất trọng internet và khi sử dụng internet chúng ta luôn phải suy nghĩ đến protocol. Người ra dựa vào giao thức để điều khiển việc nhận và gửi các message. Nó được định nghĩa:
-Giao thức là định dạng và thứ tự giao tiếp giữa 2 end system.TCP/IP là 2 giao thức quan trọng nhất của internet. Ví dụ khi chúng ta nói chuyện với nhau thì cũng có nhiều giao thức kiểu như: Phải chào trước khi hỏi, phải nói chuyện cùng ngôn ngữ, chờ người ta trả lời rồi mới hỏi tiếp …. Để mô tả và hiểu rõ hơn về giao thức chúng ta sẽ tìm hiểu về Các lớp giao thức:

Protocol Layer :

-Khi xây dựng protocol người ta đã nghĩ làm sao để dễ bảo trì và mở rộng. Thiết kế kiểu layer này không có gì là mới lạ cả. layer bên dưới sẽ cung cấp một số dịch vụ để xây dựng layer bên trên nó. Vi dụ nhà nước làm đường xá tạo ra dịch vụ để cho viettel mở viettelpost, viettelpost cung cấp dịch vụ cho người ta đăng kí làm bưu cục. bưu cục lại cung cấp dịch vụ cho người ta đến gửi hàng.
alt text

  • Các dịch dịch vụ lớp dưới cung cấp cho lớp trên ở đây là gì ? Nó chính là một hoặc nhiều giao thức. Hay nói các khác lớp dưới sẽ xây dựng 1 giao thức để cung cấp cho lớp trên sử dụng như là 1 dịch vụ. Vì vậy mô hình này gọi là protocol stack ( các lớp giao thức chồng lên nhau ). Trong khuôn khổ của bài này thực sự bạn không cần quan tâm đến tất cả 5 lớp. Hãy ghi nhớ điều này rằng: từ layer 1 đến layer 4 sẽ do hệ điều hành hoặc các thành phần khác trong mạng máy tính điều khiển. Bạn chỉ cần quan tâm đến lớp giao thức ứng dụng và những dịch vụ do transport layer cung cấp ( đó là TCP và UDP)

  • Thật vậy các giao thức mạng giúp bạn truy cập đến một phần dữ liệu của internet. Các giao thức khác nhau sẽ giúp các bạn truy cập đến các thế giới khác nhau trong internet. Hầu hết thời gian mọi người sử dụng internet là để truy cập sufaceweb qua một dịch vụ do internet cung cấp có tên là web sử dụng giao thức http. nó phát triển mạnh đến mức nhiều người nhầm tưởng nó chính là internet nhưng thật ra http cho phép chúng ta tiếp cận khoảng 4% dữ liệu của internet nơi mà thông tin bị kiểm duyệt cực mạnh bởi chính phủ để nhằm mục đích định hướng xã hội nghĩ theo cách họ muốn vì vậy một thông tin bạn tiếp cận trên internet có thể không đúng với thực tế của nó hoặc mức độ đã giảm bớt đi rất nhiều. Mình có thể chia những người sử dụng suface web thành 2 nhóm : nhóm chăn gà và nhóm những con gà. Bạn luôn là một con gà nhưng mà mức độ bị chăn dắt ntn thôi. Là một người học it bạn phải có ý thức sử dụng internet để tạo ra giá trị cho bạn chứ đừng để bị chăn dắt quá nhiều. Ở đây mình muốn giới thiệu thêm một trong những hidden internet protocol ( giao thức mạng ẩn) tên của nó là giao thức củ hành. Nó giúp các bạn truy cấp đến một phần dữ liệu deepweb lớn hơn nó chính là darknet. Nơi chiếm khoảng 96% dữ liệu của internet nghĩ về nó người ta thường nghĩ tới Chợ đen, tài liệu cấm,người ngoài hành tinh, hội nhóm bí mật….Tiếp cận Deepweb hay darknet bạn sẽ phải tự đặt ra câu hỏi bạn là gì giữa thế giới này ? bởi vì deepweb,darknet là một thế giới khác nó đang tồn tại và nó vượt qua sự tưởng tượng của hầu hết mọi người. bitcoin với sự bảo mật của nó từ lâu đã được chọn là đồng tiền của deepweb, hiện nay bitcoin đã xâm lấn sang suface web.

Cốt lõi của một network application:

Cốt lõi của 1 network application là viết các chương trình chạy trên end system khác nhau và kết nối với nhau qua mạng.Khi xây dựng 1 app bạn phải xác định kiến trúc của nó. Không cần phải suy nghĩ nhiều chỉ có 2 loại kiến trúc ở đây thôi.

Client-Sever :

Một thằng lúc nào cũng phải hoạt động ( sever ) xử lý các yêu cầu của thằng khác ( client ) qua mạng. ( các ứng dụng web: trình duyệt là client yêu cầu dữ liệu từ các máy chủ google, youtube…). Mục đích là để trao đổi dữ liệu. Giả sử tài khoản fb A muốn nhắn tin cho tài khoản fb B thì rõ ràng chúng đang là giao tiếp client - server và A,B phải giao tiếp thông qua máy chủ facebook

Peer to Peer :

Hai thằng trực tiếp kết nối với nhau để trao đổi dữ liệu. Ưu điểm lớn nhất của mô hình này là khả năng tự mở rộng. 2 ứng dụng nổi tiếng xây dựng trên mô hình Peer to Peer là bitTorrent và bitCoin. Các ứng dụng này theo mình đều mang trong nó những ý tưởng thiên tài. Với bitCoin đó là một loại tiền ảo nằm ngoài tầm kiểm soát của chính phủ người ta có thể sử dụng bitcoin để giao dịch bảo mật và miễn phí, hệ thống đào Coin đóng vai trò duy trì hoạt động của bitCoin khi một phần hệ thống bị tổn tương phần còn lại vẫn hoạt động để bảo vệ hệ thông theo nguyên tắc ưu tiên số đông. Hệ thổng máy tinh đang bảo vệ giao dịch bitcoin đã mạnh mẽ hơn bất kì một siêu máy tính nào trên thế giới. Giá trị của một đồng tiền được định giá bằng giá trị nền kinh tế đứng sau nó còn bitcoin giá trị của nó chính là giá trị của hệ thống máy tính tham gia vào đào coin có người còn cho rang bitCoin được định giá bằng giá trị của internet có nghĩ là bitcoin sẽ trở thành đồng tiền của internet và trừng nào internet chưa chết thì nó ko thể chết được. Còn bitTorrent là ứng dụng chia sẻ file khi bạn download 1 file từ Torrent bạn sẽ trở thành người chuyển tiếp file đó cho người khác. bitTorrent là ý tưởng về một ứng dụng chia sẻ dữ liệu miễn phí tốc độ cao khả năng tự mở rộng không giới hạn. Tuy nhiên nghĩ tới Torrent người ta thường nghĩ tới các nội dung vi phạm bản quyền được chia sẻ tràn lan vì tài nguyên thay vì lưu tại các trung tâm dữ liệu thì lại được lưu ở máy tính người tham gia vào hệ thống ( tình nguyện viên ) nên khó kiểm duyệt cho nên các hệ thống chia sẻ file qua Torrent lớn cứ sập liên tục.

Như đã nói từ layer 1 đến layer 4 là do hệ điều hành hoặc các thành phần khác trong mạng máy tính điều khiển. Chúng ta chỉ cần quan tâm đến phần tương tác giữ chương trình và mạng máy tính. Nghĩa là hệ điều hành sẽ điều khiển đến layer 4, nó đặt 1 trình điều khiển ở đây và bảo rằng: Bất kì một chương trình nào muốn sử dụng mạng phải đăng kí vs nó trước, sau khi đăng kí nó tạo ra cho chương trình một socket mà từ đó chương trình có thể sử dụng socket đó để giao tiếp với mạng. Như vậy chương trình sẽ gửi và nhận dữ liệu qua socket của nó. Nếu bạn quan tâm đến khái niệm thì ở đây mình cũng đưa ra một khái niệm về socket: socket chính là API giữa application layer và transport layer.
alt text

Khi lập trình socket bạn sẽ sử dụng được các dịch vụ do lớp tranport layer cung cấp. 2 dịch vụ ở đây chính là TCP và UDP.
TCP và UDP phù hợp với app network khác nhau. Giao thức udp là giao thức không kết nối nó ko đảm bảo dữ liệu trên đường truyền. TCP thì là giao thức định hướng kết nối nó đảm bảo dữ liệu trên đường truyền. TCP và UDP sẽ được mô tả cụ thể ở phần sau.UDP nhạy cảm với tường lửa vi lý do bảo mật trong bài thuyết trình này mình sẽ chỉ nói về kết nối định hướng TCP với thủ tục bắt tay 3 bước. Mình sẽ nói chi tiết hơn và TCP và UDP trong phần sau.

Ngoài TCP và UDP bạn thực sự cần quan tâm một chút đến giao thức IP ở lớp Internet vủa Protocol Stack. TCP và UCP được xây dựng trên giao thức IP. Điều duy nhất bạn cần nhớ là mỗi thiết bị kết nối vào internet đều được cấp 1 địa chỉ để xác định gọi là IP ví dụ: 117.0.171.245 Khi biết ip của một thiết bị trong internet ta mới có thể kết nối đến nó.

Mình muốn giới thiệu với các bạn 2 giao thức thông dụng ở lớp giao thức ứng dụng để các bạn có thể tự tin sử dụng socket. Đầu tiên phải kể đến http. Http sử dụng trong web mà hết thời gian sử dụng internet của các bạn đều sử dụng http. http đơn giản chỉ là các quy tắc truyền dữ liệu mà khi các thiết bị tuân thủ theo đúng quy tắc đó thì sẽ có thể giao tiếp với nhau qua mạng. Nếu các bạn đã nghe nói đến websocket thì websocket cũng có thể được coi là một giao thức giống http nhưng tối giản hơn.Và đừng nhầm lẫn khái niệm socket mình đang đề cập với Socket.io là một thư việc của JS. Giao thức thứ 2 mình nghĩ là quan trọng để nói đến ở đây là dns. Thực sự các thiết bị kết nối vào mạng chỉ có thể giao tiếp với nhau nếu biết địa chỉ ip của nhau. Nhưng địa chỉ ip thường khó nhớ nên người ta dùng hostname để thay thế. Ví dụ: facebook.com hay google.com. Khi bạn gõ vào trình duyệt facebook.com việc đầu tiên là trình duyệt dùng giao thức dns để hỏi máy chủ dns xem thằng facebook.com có địa chỉ ip là gì sau đó mới kết nối tới facebook qua địa chỉ ip của nó. Dns cung cấp dịch vụ cân bằng tải đó là lý do tại sao cùng 1 lúc cả tỉ người dùng cùng có thể truy cập vào google được. Hệ thông dns là phức tạp nhiều level tuy nhiên lại yêu cầu tốc độ cao, vì vậy người ta sử dụng cache sever để tối ưu. Dữ liệu của cache sever sẽ được làm mới sau một khoảng thời gian. Vì vậy mà khi 1 thiết lập hostname được thay đổi thì thay đổi đó có thể cần đến 24h để được cập nhập. Khi dùng socket thì các bạn nên sử dụng ip thay vì hostname.

Lập trình socket trong java

Stream : Khi socket được tạo ra, 1 luồng dữ liệu sẽ được thiết lập để trao đổi dữ liệu. Thao tác với socket sẽ chuyển thành việc thao tác với luồng vì vậy nó là quan trọng để nói tới ở đây.

alt text

  • Có 2 cách để khởi tạo 1 giá trị cho một biến: sử dụng các literal const ( trong chương trình bạn viết a=5, a="abc" thì 5, hay "abc" được gọi là literal const ) hoặc là sử dụng stream i/o ( luồng vào ra - rõ ràng luồng vào ra là khái niệm quan trọng và bạn luôn sử dụng nó trong lập trình hãy nhớ rằng 1 chương trình thực hiện 2 công việc chính là Vào ra dữ liệu và Xử lý dữ liệu). ( ra vào màn hình hay ra vào file là 1 trường hợp cụ thể của stream i/o ).
  • Luồng ở đây hiểu đơn giản là một liên kết với nguồn ( để lấy dữ liệu) hoặc với đích ( để ghi dữ liệu). Khái niệm stream trong c hay c++ nó còn mờ nhạt nhưng trong java mọi thứ trở nên rõ ràng hơn nhiều bởi vì khái niệm filter mình sắp nói dưới đây do đó mà như bạn đã thấy thấy việc ra vào file và ra vào màn hình bàn phím rất giông nhau.
  • Mình muốn nói về 2 luồng bạn các sử dụng từ khi bắt đầu học lập trình đó là stdin và stdout. Stdin được coi là cái bàn phím còn Stdout được coi là cái màn hình ( thực sự stdout được coi là cái cửa số hiện nên màn hình khi chương trình bạn đang chạy chứ ko phải cả cái màn hình). Stdin và Stdout còn có cả stderr( stderr có trong hệ thống máy tính cũ khi máy tính mới ta đời ) là 3 thành phần gọi chung với cái tên là Thiết bị đâu cuối ( Console). Khi bạn nhập dữ liệu từ bàn phím bán sẽ thấy bạn gõ là đẩy dữ liệu vào stdin nhưng lại hiện lên stdout. Điều đó làm cho stdin và stdout dính vào nhau làm nhiều người không phân biệt được stdin và stdout. Khi chưng trình bạn chạy bạn gõ bất cứ thứ gì thì dữ liệu đều được đẩy vào stdin dù nó có được hiển thị nên stdout hay không ? Hàm cơ bản nhất là là scanf trong C hoạt động thế nào? Nó dừng chương trình lại để nhận dữ liệu từ stdin và nhận đến khi nào bạn nhập vào kí tự blank ( trong trường hợp này là \n) thì mới dừng lại. Nếu bạn chơi SPOJ bạn có hiểu là cơ chế test code của bạn như thế nào không. Đơn giản nó chỉ cần chạy code của bạn đẩy vào stdin một bộ test và kiểm tra stdout. Không quan trọng code bạn như thế nào miễn là stdout đúng với bộ test.
    alt text

  • Hai luồng cơ bản nhất trong java là byte stream (class InputStream, OutputStream) và character stream ( Reader, Writer). Cả 2 luồng này đều có 2 phương thức cơ bản là read() và write(). Với byte stream là đọc và ghi một số thuộc kiểu byte không dấu vì java ko có kiểu byte không dấu nên 1 số int được sử dụng thay thế. Với là character stream thì là đọc ghi 1 số int 2byte ( 0->2^16 ).

  • Luồng byte thì rất dễ hiểu nhưng luồng kí tự thì phức tạp hơn một chút.Luồng byte thì cứ đọc 1 byte một lần còn ký tự có thể có nhiều byte vậy làm sao luồng ký tự đọc đến 1 byte nó biết byte đó thuộc ký tự nào và ký tự đó có mấy byte cùng xem xét về khái niệm charset để hiểu rõ về luồng kí tự. Mọi người hay nhầm lẫn ascii hay unicode là một loại mã hóa nhưng thật ra ascii hay unicode chỉ là một bảng mã. Trên bảng mã đó mỗi kí tự có một giá trị nhất định với tư duy là khi trong chương trình nếu bạn viết ‘A’ thì máy tính hiểu đó là giá trị của ‘A’ là 65 trên bảng mã. Vì vậy character cũng có các phép toán + - * / như các kiểu dữ liệu số học. Việc biểu diễn giá trị của ‘A’ là 65 vào máy tính được gọi là kiểu mã hóa kí tự ( charset ). Với ascii vì là các kí tự có giá trị 1 byte nên nó đơn giản là chuyển 65 từ hệ 10 sang hệ nhị phân thôi ( Kiểu mã hóa này được gọi là ASCII luôn). Với unicode các giá trị có độ dài 2 byte nếu biểu diễn giống kiểu ascii tức là đổi sang hệ nhị phân thì rõ ràng các tài liệu đã viết bằng ascii bây giờ chuyển sang unicode có dung lượng tăng gấp đối ( utf16 hoặc là unicode). Vì vậy utf8 ra đời để mã hóa bảng mã unicode. Nó giữ nguyên các kí tự ascii, 0-127 vẫn để 1 byte nhưng từ 127 đổi lên sẽ biểu diễn thành 2 hoặc 3 byte. Utf8 vì vậy mà được cho là tương thích ngược với ascii và được sử dụng rộng rãi ngày nay. Khi dùng luồng kí tự thì có nghĩa là chương trình sẽ đọc từng byte một vậy làm sao chương trình biết là kí tự đang đọc là 1 byte, 2byte hay 3byte vì vậy bạn phải xác định được loại charset cho luồng kí tự.
    alt text

  • Từ 2 luồng cơ bản này người ta xây dựng những luồng khác trên nó để mở rộng các thao tác. Ví dụ : DataInput và DataOutput sử dụng byte stream để thực hiện đọc ghi các kiểu dữ liệu nguyên thủy ( các kiểu dữ liệu không phải là object thì là nguyên thủy) và PrintWriter sử dụng character stream để thực hiện ghi dữ liệu theo định dạng. Những luồng xây dựng trên luồng cơ bản được gọi là các Filter ( bộ lọc). Như vậy chúng ta có 2 khái niệm là Luồng cơ bản và Filter. Mội đối tượng là filter thì kiểu gì nó cũng có constructor khởi tạo bằng cách sử dụng basic stream bởi vì filter được xây dựng trên basic stream.

  • Thực sự byte stream là luồng cơ bản nhất vì vậy mà tất cả các luồng khác được coi là filter của nó theo đúng tư duy của Filter. Nghĩa là character stream cũng là filter của byte stream nhưng mà vì đây đều là luồng hay dùng nên nó được tách nhau ra và được gọi là luồng cơ bản ( basic stream )

  • Khái niệm filter ở đây mình nói khác với FilterInpuStream hay FilterReader trong java. Nó mở rộng hơn và tổng quát hơn. FilterInpuStream, hay ObjectInputStream đều được coi là filter. Khác biệt tại sao ObjectInputStream kế thừa FilterInpuStream thì do constructor của nó FilterInpuStream chỉ có 1 constructor duy nhất và nhận vào một basic stream để khởi tạo.
    alt text

  • Câu lệnh này khởi tạo một đối tượng PrintWriter nhưng rõ ràng câu lệnh này không thể hiện được tính chất filter của PrintWinter
    alt text

  • Câu lệnh thể hiện tính chất filter của PrintWriter
    alt text

  • Scanner và Formating: Lập trình viên thường muốn chuyển đổi dữ liệu đầu vào và định dạng dữ liệu đầu ra sao cho có thể đọc và hiểu được. Ví dụ: Scanner hỗ trợ sử dụng biểu thức chính quy để phân chia dữ liệu luồng vào ( new Scanner(System.in) đối tượng System.in là byte stream ) thành các token sau đó chuyển đổi thành các kiểu dữ liệu bạn mong muốn, System.out là một đối tượng PrintStream có các hàm để bạn định dạng dữ liệu đầu ra . Lưu ý có 3 class giúp bạn thực hiện scan và format là: Scanner và PrintStream , PrintWriter. Nếu nói đến 3 class này nhiều bạn nghĩ ngay đến đây là các class thực hiện vào ra theo kiểu văn bản nhưng liệu có cần phân biệt ra vào nhị phân và ra vào văn bản không ?. Nếu nói PrintStream là vào ra nhị phân thì hãy suy nghĩ là đối được System.out bạn hay sử dụng. Nếu nói Reader ,Writer là là vào ra văn bản thì thực ra nó chỉ là một luồng đọc ghi kí tự theo một kiểu mã hóa định trước mà thôi.

..... Phần 2: Nói về tcp sử dụng giao thức http trong java. . Chương trình của bạn bị tiêu tốn nhiều thời gian ở việc vào ra dữ liệu hơn là xử lý dữ liệu rất nhiều lần vì vậy mình sẽ nói tới cả: "Việc sử lý i.o bằng đa luồng, đa tiến trình, nonblocking i.o ". ( đang viết )

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

White

Thuong Nguyen Van

1 bài viết.
5 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


White
{{userFollowed ? 'Following' : 'Follow'}}
1 bài viết.
5 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!