1. Trang chủ
  2. » Giáo Dục - Đào Tạo

BÁO CÁO CHI TIẾT LẬP TRÌNH MẠNG đề tài SOCKET FOR CLIENTS SOCKET FOR SERVERS

90 5 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Socket For Clients Socket For Servers
Tác giả Nguyễn Thị Thùy Linh, Hoàng Trung Công, Nguyễn Văn An, Nguyễn Mạnh Thắng
Người hướng dẫn ThS. Nguyễn Mạnh Hùng
Trường học Trường Đại Học Kiến Trúc Hà Nội
Chuyên ngành Công Nghệ Thông Tin
Thể loại báo cáo
Năm xuất bản 2021
Thành phố Hà Nội
Định dạng
Số trang 90
Dung lượng 2,22 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

• Chấp nhận kết nối từ các máy từ xa trên cổng ràng buộcLớp Socket của Java , được sử dụng bởi cả khách hàng và máy chủ, có các phương pháp tương ứng với bốn hoạt động đầu tiên trong sốn

Trang 1

TRƯỜNG ĐẠI HỌC KIẾN TRÚC HÀ NỘI KHOA CÔNG NGHỆ THÔNG TIN

BÁO CÁO CHI TIẾTLẬP TRÌNH MẠNG

Thành viên nhóm :

1 Nguyễn Thị Thùy Linh 1855010094

Trang 2

Mục Lục

CHƯƠNG I: SOCKET FOR CLIENTS 4

1.1 Sử dụng socket 4

1.1.1 Điều tra giao thức với Telnet 5

1.1.2 Đọc từ máy chủ có socket 8

1.1.3 Viết vào máy chủ có socket 18

1.2 Xây dựng và kết nối socket 26

1.2.1 Nhà xây dựng cơ bản 26

1.2.2 Xây dựng mà không cần kết nối 29

1.2.3 Địa chỉ socket 31

1.2.4 Máy chủ Proxy 32

1.3 Nhận thông tin về socket 34

1.3.1 Đã đóng hoặc Đã kết nối? 36

1.4 Tùy chọn cài đặt socket 38

1.5 Ngoại lệ socket 38

1.6 Socket trong ứng dụng GUI 39

1.6.1 Whois 40

1.6.2 A netwworl client library 43

CHƯƠNG II: SOCKET FOR SERVERS 51

2.1 Sử dụng ServerSockets 51

2.1.1 Phục vụ dữ liệu nhị phân 57

2.1.2 Máy chủ đa luồng 58

2.1.3 Viết vào máy chủ có socket 62

2.1.4Đóng socket Máy chủ 63

2.2 Đăng nhập 66

2.2.1 what to log 66

Trang 3

2.2.2 Cách đăng nhập 67

2.3 Xây dựng server socket 70

2.3.1 Xây dựng mà không có ràng buộc 72

2.4 Lấy thông tin về server socket 74

2.5 Tùy chọn socket 75

2.5.1 SO_TIMEOUT 75

2.5.2 SO_REUSEADDR 76

2.5.3 SO_RCVBUF 76

2.5.4 Lớp dịch vụ 78

2.6 Máy chủ HTTP 79

2.6.1 Máy chủ Một Tệp 80

2.6.2 Bộ chuyển hướng 84

2.6.3 Máy chủ HTTP chính thức 86

Trang 4

CHƯƠNG I: SOCKET FOR CLIENTS

Dữ liệu được truyền qua Internet trong các gói có kích thước

hữu hạn được gọi là datagrams Mỗi datagram chứa một tiêu đề và một tải trọng Tiêu đề chứa địa chỉ và cổng mà gói tin đang đi, địa

chỉ và cổng mà gói tin đến, séc để phát hiện tham nhũng dữ liệu vànhiều thông tin vệ sinh khác được sử dụng để đảm bảo truyền tảiđáng tin cậy Tải trọng chứa chính dữ liệu Tuy nhiên, vì datagram

có độ dài hữu hạn, nên thường cần phải chia dữ liệu trên nhiều gói

và lắp ráp lại tại điểm đến Cũng có thể một hoặc nhiều gói có thể bịmất hoặc bị hỏng trong quá trình vận chuyển và cần phải đượctruyền lại hoặc các gói đến ngoài trật tự và cần phải được sắp xếplại Theo dõi điều này - chia dữ liệu thành các gói, tạo tiêu đề, phântích tiêu đề của các gói đến, theo dõi những gói nào đã và chưa đượcnhận, v.v - là rất nhiều công việc và đòi hỏi rất nhiều mã phức tạp

May mắn thay, bạn không cần phải tự mình thực hiện côngviệc Socket cho phép lập trình viên xử lý kết nối mạng chỉ là mộtluồng khác mà byte có thể được viết và từ đó có thể đọc byte Socketbảo vệ lập trình viên khỏi các chi tiết cấp thấp của mạng, chẳng hạnnhư phát hiện lỗi, kích thước gói, tách gói, truyền lại gói, địa chỉmạng và hơn thế nữa

Trang 5

• Chấp nhận kết nối từ các máy từ xa trên cổng ràng buộc

Lớp Socket của Java , được sử dụng bởi cả khách hàng và máy chủ,

có các phương pháp tương ứng với bốn hoạt động đầu tiên trong sốnày Ba thao tác cuối cùng chỉ cần thiết bởi các máy chủ, chờ kháchhàng kết nối với họ Chúng được thực hiện bởi lớp ServerSocket,được thảo luận trong chương tiếp theo Các chương trình Javathường sử dụng socket máy khách theo cách sau:

• Chương trình tạo ra một socket mới với một constructor

• Socket cố gắng kết nối với máy chủ từ xa

Khi kết nối được thiết lập, các máy chủ cục bộ và từ xa sẽ nhậnđược các luồng đầu vào và đầu ra từ socket và sử dụng các luồng đó

để gửi dữ liệu cho nhau Kết nối này là full-duplex Cả hai máy chủ

có thể gửi và nhận dữ liệu cùng một lúc Dữ liệu có nghĩa là gì phụthuộc vào giao thức; các lệnh khác nhau được gửi đến máy chủ FTP

so với máy chủ HTTP Thông thường sẽ có một số cái bắt tay đượcthỏa thuận, tiếp theo là việc truyền dữ liệu từ cái này sang cái khác.Khi việc truyền dữ liệu hoàn tất, một hoặc cả hai bên đóng kết nối.Một số giao thức, chẳng hạn như HTTP 1.0, yêu cầu kết nối phảiđược đóng sau mỗi yêu cầu được phục vụ Những người khác, chẳnghạn như FTP và HTTP 1.1, cho phép nhiều yêu cầu được xử lý trongmột kết nối duy nhất

1.1.1 Điều tra giao thức với Telnet

Trong chương này, bạn sẽ thấy khách hàng sử dụng socket đểgiao tiếp với một số dịch vụ Internet được biết đến như thời gian, sắclệnh và hơn thế nữa Bản thân các socket đủ đơn giản; tuy nhiên, cácgiao thức để giao tiếp với các máy chủ khác nhau làm cho cuộc sốngtrở nên phức tạp

Để có được cảm giác về cách một giao thức hoạt động, bạn có thể sửdụng Telnet để kết nối với máy chủ, nhập các lệnh khác nhau cho nó

Trang 6

và xem phản hồi của nó Theo mặc định, Telnet cố gắng kết nối vớicổng 23 Để kết nối với máy chủ trên các cổng khác nhau, hãy chỉđịnh cổng bạn muốn kết nối như sau:

$ telnet localhost 25

Điều này yêu cầu kết nối với cổng 25, cổng SMTP, trên máy cụcbộ; SMTP là giao thức được sử dụng để chuyển email giữa các máychủ hoặc giữa máy khách thư và máy chủ Nếu bạn biết các lệnh đểtương tác với máy chủ SMTP, bạn có thể gửi email mà không cầnthông qua chương trình thư Thủ thuật này có thể được sử dụng đểgiả mạo email Ví dụ, một vài năm trước, các sinh viên mùa hè tạiĐài quan sát năng lượng mặt trời quốc gia ở Sunspot, New Mexico,

đã làm cho nó xuất hiện rằng bữa tiệc mà một trong những nhà khoahọc đã ném sau trận đấu bóng chuyền hàng năm giữa các nhân viên

và các sinh viên trên thực tế là một bữa tiệc chiến thắng cho các sinhviên (Tất nhiên, tác giả của cuốn sách này hoàn toàn không liênquan gì đến hành vi đê hèn như vậy.;-) ) Sự tương tác với máy chủSMTP đã diễn ra như thế này; nhập các loại người dùng được hiểnthị in đậm (tên đã được thay đổi để bảo vệ người cả tin):

Trang 7

Một số nhân viên đã hỏi Bart tại sao anh ta, một nhân viên, lại tổchức một bữa tiệc chiến thắng cho các sinh viên Đạo đức của câuchuyện này là bạn không bao giờ nên tin tưởng email, đặc biệt làemail vô lý như thế này, mà không có xác minh độc lập Trong 20năm kể từ khi điều này xảy ra, hầu hết các máy chủ SMTP đã thêmmột chút bảo mật hơn so với hiển thị ở đây Họ có xu hướng yêu cầutên người dùng và mật khẩu, và chỉ chấp nhận kết nối từ khách hàngtrong các mạng cục bộ và các máy chủ thư đáng tin cậy khác Tuynhiên, bạn vẫn có thể sử dụng Telnet để mô phỏng máy khách, xemmáy khách và máy chủ tương tác như thế nào và do đó tìm hiểu xemchương trình Java của bạn cần làm gì Mặc dù phiên này khôngchứng minh tất cả các tính năng của giao thức SMTP, nhưng nó đủ

Trang 8

để cho phép bạn suy luận cách một ứng dụng email đơn giản nóichuyện với máy chủ.

1.1.2 Đọc từ máy chủ có socket

Hãy bắt đầu với một ví dụ đơn giản Bạn sẽ kết nối với máychủ ban ngày tại Viện Tiêu chuẩn và Công nghệ Quốc gia (NIST) vàyêu cầu nó cho thời điểm hiện tại Giao thức này được định nghĩatrong RFC 867 Đọc điều đó, bạn thấy rằng máy chủ ban ngày nghetrên cổng 13 và máy chủ gửi thời gian ở định dạng có thể đọc đượccủa con người và đóng kết nối Bạn có thể kiểm tra máy chủ banngày với Telnet như thế này:

Dòng "56375 13-03-24 13:37:50 50 0 888.8 UTC (NIST)" được gửibởi máy chủ ban ngày Khi bạn đọc InputStream của Socket, đây lànhững gì bạn sẽ nhận được Các dòng khác được sản xuất bởi vỏUnix hoặc bởi chương trình Telnet

RFC 867 không chỉ định bất kỳ định dạng cụ thể nào cho đầu rangoài việc nó có thể đọc được của con người Trong trường hợp này,bạn có thể thấy kết nối này được thực hiện vào ngày 24 tháng 3 năm

2013, lúc 1:37: 50 P.M., Greenwich Meantime Cụ thể hơn, định

dạng được định nghĩa là JJJJJ

YY-MM-DD HH:MM:SS TT L H msADV UTC(NIST) OTM trong đó:

JJJJJ là "Ngày Julian sửa đổi" (tức là, đó là số ngày kể từ nửa

đêm ngày 17 tháng 11 năm 1858)

YY-MM-DD là hai chữ số cuối cùng của năm, tháng và ngày hiện

tại của tháng

Trang 9

HH: MM: SS là thời gian tính bằng giờ, phút và giây trong Giờ

phối hợp toàn cầu (UTC, về cơ bản là Giờ trung bìnhGreenwich)

TT cho biết liệu Hoa Kỳ hiện đang tuân thủ giờ chuẩn hay giờ

tiết kiệm ánh sáng ban ngày: 00 có nghĩa là thời gian tiêu chuẩn;

50 có nghĩa là thời gian tiết kiệm ánh sáng ban ngày Các giá trịkhác đếm ngược số ngày cho đến khi chuyển đổi

L là một mã có một chữ số cho biết liệu một giây nhuận sẽ được

thêm hoặc trừ vào nửa đêm vào ngày cuối cùng của tháng hiệntại: 0 cho không có giây nhuận, 1 để thêm giây nhuận và 2 để trừ

đi một giây nhuận

H đại diện cho sức khỏe của máy chủ: 0 có nghĩa là khỏe mạnh,

1 có nghĩa là lên đến 5 giây tắt, 2 có nghĩa là hơn 5 giây tắt, 3 cónghĩa là một số lượng không chính xác không xác định, và 4 làchế độ bảo trì

msADV là một số mili giây mà NIST thêm vào thời gian nó gửi

để bù đắp cho sự chậm trễ của mạng Trong mã trước, bạn có thểthấy rằng nó đã thêm 888,8 mili giây vào kết quả này, bởi vì đó

là thời gian nó ước tính sẽ mất để phản hồi trở lại

Chuỗi UTC (NIST) là một hằng số, và OTM gần như là một hằng

số (một dấu hoa thị trừ khi có điều gì đó thực sự kỳ lạ đã xảy ra).Những chi tiết này đều là NIST cụ thể Chúng không phải là mộtphần của tiêu chuẩn ban ngày Mặc dù chúng cung cấp rất nhiều dữliệu, nhưng nếu bạn có nhu cầu lập trình thực sự để đồng bộ hóa vớimáy chủ thời gian mạng, bạn nên sử dụng giao thức NTP được xácđịnh trong RFC 5905 thay thế

Tôi không chắc ví dụ này sẽ hoạt động trongbao lâu như được hiển thị ở đây Các máy chủnày bị quá tải và tôi đã gặp sự cố liên tục khikết nối trong khi viết chương này Vào đầu năm 2013,

Trang 10

NISTđã đưa ra một danh từ, "Người dùng giao thức NIST

DAYTIME trên cổng TCP 13 cũng được khuyến khích

mạnh mẽ để nâng cấp lên giao thức thời gian mạng, cung

cấp độ chính xác cao hơn và yêu cầu băng thông mạng ít

hơn Máy khách thời gian NIST (nistime-32bit.exe) hỗ trợ

cả hai giao thức Chúng tôi hy vọng sẽ thay thế phiên bản

tcp của giao thức này bằng một phiên bản udpbased gần

cuối năm 2013" Tôi sẽ chỉ cho bạn cách truy cập dịch vụ

này qua UDP trong Chương 11

Bây giờ chúng ta hãy xem làm thế nào để truy xuất dữ liệu tương tựnày theo chương trình bằng cách sử dụng socket Đầu tiên, mở

socket để time.nist.gov trên cổng 13:

Điều này không chỉ tạo ra đối tượng Nó thực sự làm cho kết nốitrên mạng Nếu kết nối hết thời gian hoặc thất bại vì máy chủ khôngnghe trên cổng 13, thì người xây dựng sẽ ném IOException, vì vậybạn thường sẽ bọc điều này trong một khối thử Trong Java 7,Socket triển khai Autocloseable để bạn có thể sử dụng try-with-resources:

Trong Java 6 trở về trước, bạn sẽ muốn đóng rõ ràng socket trongmột khối cuối cùng để giải phóng tài nguyên mà socket nắm giữ:

Trang 11

Mặc dù một socket sẽ ném ConnectException khá nhanh nếu máychủ từ chối kết nối hoặc NoRouteToHostException nếu các bộ địnhtuyến không thể tìm ra cách gửi gói tin của bạn đến máy chủ, cả haiđều không giúp bạn trong trường hợp máy chủ hoạt động sai chấpnhận kết nối và sau đó ngừng nói chuyện với bạn mà không chủđộng đóng kết nối Đặt thời gian chờ trên socket có nghĩa là mỗi lầnđọc hoặc ghi vào socket sẽ mất nhiều nhất một số mili giây nhấtđịnh Nếu một máy chủ bị treo trong khi bạn đang kết nối với nó,bạn sẽ được thông báo bằng SocketTimeoutException Chính xácthời gian chờ bao lâu để thiết lập phụ thuộc vào nhu cầu của ứngdụng của bạn và mức độ đáp ứng mà bạn mong đợi máy chủ Mườilăm giây là một thời gian dài để một máy chủ intranet cục bộ phản

Trang 12

hồi, nhưng nó khá ngắn đối với một máy chủ công cộng quá tải như

time.nist.gov.

Khi bạn đã mở socket và đặt thời gian chờ, hãy gọi getInputStream()

để trả về InputStream bạn có thể sử dụng để đọc byte từ socket Nóichung, một máy chủ có thể gửi bất kỳ byte nào cả; nhưng trongtrường hợp cụ thể này, giao thức quy định rằng các byte đó phải làASCII:

Ở đây tôi đã lưu trữ các byte trong stringbuilder Tất nhiên, bạn cóthể sử dụng bất kỳ cấu trúc dữ liệu nào phù hợp với vấn đề của bạn

để giữ dữ liệu ra khỏi mạng

Ví dụ 8-1 đặt tất cả điều này lại với nhau trong một chương trìnhcũng cho phép bạn chọn một máy chủ ban ngày khác nhau

Trang 13

Đầu ra điển hình giống như nếu bạn kết nối với Telnet:

$ java DaytimeClient

56375 13-03-24 15:05:42 50 0 843.6 UTC(NIST) *

Theo như mã mạng cụ thể, đó là khá nhiều nó Trong hầu hết cácchương trình mạng như thế này, nỗ lực thực sự là nói giao thức vàhiểu các định dạng dữ liệu Ví dụ: thay vì chỉ đơn giản là in ra vănbản mà máy chủ gửi cho bạn, bạn có thể muốn phân tích nó thànhmột đối tượng java.util.Date thay thế Ví dụ 8-2 cho bạn thấy làmthế nào để làm điều này Đối với sự đa dạng, tôi cũng đã viết ví dụnày tận dụng lợi thế của AutoCloseable của Java 7 và thử với các tàinguyên

Trang 14

Tuy nhiên, lưu ý rằng lớp này không thực sự làm bất cứ điều gì vớimạng mà Ví dụ 8-1 không làm Nó chỉ cần thêm một loạt các mã đểbiến chuỗi thành ngày Khi đọc dữ liệu từ mạng, điều quan trọng cầnlưu ý là không phải tất cả các giao thức đều sử dụng ASCII hoặcthậm chí là văn bản Ví dụ, giao thức thời gian được chỉ định trong

RFC 868 quy định rằng thời gian được gửi là số giây kể từ nửa đêm,ngày 1 tháng 1 năm 1900, Giờ trung bình Greenwich Tuy nhiên,

Trang 15

điều này không được gửi dưới dạng chuỗi ASCII như 2.524.521.600hoặc -1297728000 Thay vào đó, nó được gửi dưới dạng một số nhịphân 32 bit, không có chữ ký, lớn.

RFC không bao giờ thực sự xuất hiện và nóirằng đây là định dạng được sử dụng Nó chỉđịnh 32 bit và giả định rằng bạn biết rằng tất cảcác giao thức mạng đều sử dụng số lớn Thực tế là số

không được ký chỉ có thể được xác định bằng cách tính

ngày bao quanh cho các số nguyên đã ký và không ký và

so sánh nó với ngày được đưa ra trong đặc điểm kỹ thuật

(2036) Để làm cho vấn đề tồi tệ hơn, đặc điểm kỹ thuật

đưa ra một ví dụ về thời gian tiêu cực mà không thể thực

sự được gửi bởi các máy chủ thời gian tuân theo giao thức

Thời gian là một giao thức tương đối cũ, được tiêu chuẩn

hóa vào đầu những năm 1980 trước khi IETF cẩn thận về

các vấn đề như ngày nay Tuy nhiên, nếu bạn thấy mình

thực hiện một giao thức không được chỉ định rõ ràng, bạn

có thể phải thực hiện một số lượng thử nghiệm đáng kể so

với các triển khai hiện có để tìm ra những gì bạn cần làm

Trong trường hợp xấu nhất, các triển khai khác nhau có thể

hoạt động khác nhau

Bởi vì giao thức thời gian không gửi lại văn bản, bạn không thể dễdàng sử dụng Telnet để kiểm tra một dịch vụ như vậy và chươngtrình của bạn không thể đọc phản hồi máy chủ bằng Reader hoặc bất

kỳ loại phương pháp readLine() nào Một chương trình Java kếtnối với các máy chủ thời gian phải đọc các byte thô và giải thíchchúng một cách thích hợp Trong ví dụ này, công việc đó rất phứctạp do Java thiếu loại số nguyên 32 bit không có chữ ký Do đó, bạnphải đọc byte một tại một thời điểm và chuyển đổi thủ công chúng

Trang 16

thành một thời gian dài bằng cách sử dụng các toán tử bitwise << và

|

Ví dụ 8-3 cho thấy Khi nói các giao thức khác, bạn có thể gặp phảicác định dạng dữ liệu thậm chí còn xa lạ hơn với Java Ví dụ, mộtvài giao thức mạng sử dụng số điểm cố định 64 bit Không có phímtắt để xử lý tất cả các trường hợp có thể xảy ra Bạn chỉ cần nghiếnrăng và mã hóa toán học bạn cần để xử lý dữ liệu ở bất kỳ định dạngnào mà máy chủ gửi

Trang 18

Dưới đây là kết quả của chương trình này từ một bản chạy mẫu:

$ java time

It í sun Mar 24 12:22:17 EDT 2013

Giao thức thời gian thực sự chỉ định Greenwich Mean Time, nhưngphương pháp toString() trong lớp Date của Java, đượcsystem.out.println ()ngầm gọi, chuyển đổi điều này thành múi giờcủa máy chủ địa phương, Eastern Daylight Time trong trường hợpnày

1.1.3 Viết vào máy chủ có socket

Viết cho một máy chủ không khó hơn đáng kể so với đọc từmột Bạn chỉ cần yêu cầu socket cho một luồng đầu ra cũng như mộtluồng đầu vào Mặc dù có thể gửi dữ liệu qua socket bằng cách sửdụng luồng đầu ra cùng một lúc bạn đang đọc dữ liệu qua luồng đầuvào, hầu hết các giao thức được thiết kế để khách hàng đang đọchoặc viết qua socket, không phải cả hai cùng một lúc Trong môhình phổ biến nhất, khách hàng gửi yêu cầu Sau đó, server trả lời

Trang 19

Khách hàng có thể gửi yêu cầu khác và máy chủ trả lời lại Điều nàytiếp tục cho đến khi một bên hoặc bên kia được thực hiện và đóngkết nối.

Một giao thức TCP hai chiều đơn giản là dict, được định nghĩa trong

RFC 2229 Trong giao thức này, máy khách mở một socket đếncổng 2628 trên máy chủ dict và gửi các lệnh như "DEFINE eng-lat

gold" Điều này yêu cầu máy chủ gửi một định nghĩa về từ vàng

bằng cách sử dụng từ điển tiếng Anh sang tiếng Latinh của nó (Cácmáy chủ khác nhau có các từ điển khác nhau được cài đặt.) Sau khinhận được định nghĩa đầu tiên, khách hàng có thể yêu cầu một địnhnghĩa khác Khi nó được thực hiện, nó sẽ gửi lệnh "bỏ cuộc" Bạn cóthể khám phá dict với Telnet như thế này:

$ telnet dict.org 2628

Trying

216.18.20.172

Connected to dict.org

Bạn có thể thấy rằng các dòng phản hồi điều khiển bắt đầu bằng một

mã có ba chữ số Định nghĩa thực tế là văn bản thuần túy, chấm dứtvới một khoảng thời gian trên một dòng của chính nó Nếu từ điển

Trang 20

không chứa từ bạn yêu cầu, nó trả về 552 không khớp Tất nhiên,bạn cũng có thể tìm ra điều này, và nhiều hơn nữa, bằng cách đọcRFC.

Không khó để thực hiện giao thức này trong Java Đầu tiên, mở mộtsocket vào một máy chủ dict— _dict.org là một socket tốt—trêncổng 2628:

Socket socket = new socket("dict.org", 2628);

Một lần nữa, bạn sẽ muốn đặt thời gian chờ trong trường hợp máychủ bị treo trong khi bạn đang kết nối với nó:

socket.setSoTimeout(15000);

Trong giao thức dict, khách hàng nói trước, vì vậy hãy yêu cầuluồng đầu ra bằng cách sử dụng getOut putStream():

OutputStream out = socket.getOutputStream();

Phương pháp getOutputStream() trả về một OutputStream thô đểghi dữ liệu từ ứng dụng của bạn sang đầu kia của socket Bạn thườngxích luồng này sang một lớp thuận tiện hơn như DataOutputStreamhoặc OutputStreamWriter trước khi sử dụng nó Vì lý do hiệu suất,

đó là một ý tưởng tốt để đệm nó là tốt Bởi vì giao thức dict dựa trênvăn bản, cụ thể hơn là dựa trên UTF-8, thật thuận tiện để bọc điềunày trong Một Nhà văn:

Writer writer = New

OutputStreamWriter(out,"UTF-8");

Bây giờ viết lệnh trên socket:

write.write("DEFINE eng-lat gold\r\n");

Cuối cùng, xả đầu ra để bạn chắc chắn lệnh được gửi qua mạng:writer.flush ();

Máy chủ bây giờ sẽ trả lời với một định nghĩa Bạn có thể đọc rằngbằng cách sử dụng luồng nhập của socket:

Trang 21

InputStream in = socket.getInputStream();

BufferedReader reader = new BufferedReader(

new InputStreamReader(in, "UTF-8"));

for (String line = reader.readLine();

writer.write ("quit\r\n");

writer.flush ();

Ví dụ 8-4 cho thấy một khách hàng hoàn toàn dict Nó kết nối với

dict.org và dịch bất kỳ từ nào người dùng nhập vào dòng lệnh sang

tiếng Latinh Nó lọc ra tất cả các dòng siêu dữ liệu bắt đầu bằng các

mã phản hồi như 150 hoặc 220 Tuy nhiên, nó đặc biệt kiểm tra mộtdòng bắt đầu "552 không khớp" trong trường hợp máy chủ khôngnhận ra từ đó

Ví dụ 8-4 Một dịch giả tiếng Anh sang tiếng Latin dựa trên mạng

Trang 23

Đây là một mẫu chạy:

Trang 24

í dụ 8-4 là dòng định hướng Nó đọc một dòng đầu vào từ bảng điềukhiển, gửi nó đến máy chủ và chờ đợi để đọc một dòng đầu ra mà nónhận được trở lại

Socket nửa kín

Phương pháp đóng () tắt cả đầu vào và đầu ra từ socket Đôi khi, bạn

có thể chỉ muốn tắt một nửa kết nối, đầu vào hoặc đầu ra Cácphương pháp shutdownInput() và shutdownOutput() chỉ đóng mộtnửa kết nối:

public void shutdownInput() throws IOException

public void shutdownOutput() throws IOException

Cả hai đều không thực sự đóng socket Thay vào đó, họ điều chỉnhluồng kết nối với socket để nó nghĩ rằng nó ở cuối luồng Đọc thêm

từ luồng đầu vào sau khi tắt trả về đầu vào -1 Tiếp tục ghi vàosocket sau khi tắt đầu ra ném một IOException

Trang 25

Nhiều giao thức, chẳng hạn như ngón tay, whois và HTTP, bắt đầuvới việc khách hàng gửi yêu cầu đến máy chủ, sau đó đọc phản hồi.

Có thể tắt đầu ra sau khi khách hàng đã gửi yêu cầu Ví dụ: đoạn mãnày gửi yêu cầu đến máy chủ HTTP và sau đó tắt đầu ra, bởi vì nó sẽkhông cần phải viết bất cứ điều gì khác trên socket này:

Lưu ý rằng mặc dù bạn tắt một nửa hoặc thậm chí cả hai nửa của kếtnối, bạn vẫn cần phải đóng socket khi bạn đang thông qua với nó.Các phương pháp tắt máy chỉ đơn giản là ảnh hưởng đến các luồngcủa socket Họ không giải phóng các tài nguyên liên quan đếnsocket, chẳng hạn như cổng mà nó chiếm giữ

Các phương pháp isInputShutdown() và isOutputShutdown() chobạn biết liệu các luồng đầu vào và đầu ra lần lượt được mở hayđóng Bạn có thể sử dụng chúng (thay vì được kết nối() vàisClosed()) để xác định cụ thể hơn xem bạn có thể đọc hoặc viết vàosocket:

public boolean isInputShutdown()

public boolean isOutputShutdown()

Trang 26

1.2 Xây dựng và kết nối socket

Lớp java.net.Socket là lớp cơ bản của Java để thực hiện cáchoạt động TCP phía máy khách Các lớp hướng đến khách hàng kháctạo ra các kết nối mạng TCP như URL, URLConnection, Applet vàJEditorPane cuối cùng đều kết thúc bằng cách gọi các phương phápcủa lớp này Bản thân lớp này sử dụng mã gốc để giao tiếp với ngănxếp TCP cục bộ của hệ điều hành máy chủ

1.2.1 Nhà xây dựng cơ bản

Mỗi trình xây dựng Socket chỉ định máy chủ và cổng để kếtnối Máy chủ có thể được chỉ định là InetAddress hoặc String Cổng

từ xa được chỉ định là giá trị int từ 1 đến 65535:

public Socket(String host, int port) throwsUnknownHostException, IOException public Socket(InetAddresshost, int port) throws IOException

Các nhà xây dựng này kết nối socket (tức là, trước khi trìnhxây dựng trở lại, kết nối mạng đang hoạt động được thiết lập với máychủ từ xa) Nếu kết nối không thể được mở vì một lý do nào đó,người xây dựng sẽ ném IOException hoặc tion UnknownHostExcep.Chẳng hạn:

Trong trình xây dựng này, đối số máy chủ chỉ là một tên máy chủđược thể hiện dưới dạng Chuỗi Nếu máy chủ tên miền không thểgiải quyết tên máy chủ hoặc không hoạt động, người xây dựng sẽném UnknownHostException Nếu socket không thể được mở vì một

số lý do khác, người xây dựng ném một IOException Có nhiều lý dokhiến nỗ lực kết nối có thể thất bại: máy chủ mà bạn đang cố gắng

Trang 27

tiếp cận có thể không chấp nhận kết nối trên cổng đó, dịch vụ WiFicủa khách sạn có thể chặn bạn cho đến khi bạn đăng nhập vào trangweb của nó và trả 14,95 đô la hoặc các vấn đề định tuyến có thể ngăncác gói của bạn đến đích.

Bởi vì trình xây dựng này không chỉ tạo ra một đối tượngSocket mà còn cố gắng kết nối socket với máy chủ từ xa, bạn có thể

sử dụng đối tượng để xác định xem các kết nối đến một cổng cụ thể

có được phép hay không, như trong Ví dụ 8-5

Ví dụ 8-5 Tìm hiểu cổng nào trong số 1024 cổng đầu tiên dường như đang lưu trữ máy chủ TCP trên một máy chủ được chỉ định

Đây là đầu ra mà chương trình này tạo ra trên máy chủ địa phươngcủa tôi (kết quả của bạn sẽ khác nhau, tùy thuộc vào cổng nào bịchiếm đóng):

Trang 28

Nếu bạn tò mò về những máy chủ nào đang chạy trên các cổng này,hãy thử thử nghiệm với Telnet Trên hệ thống Unix, bạn có thể tìm ra

dịch vụ nào nằm trên cổng nào bằng cách tìm kiếm trong tệp / vv / dịch vụ Nếu LowPortScanner tìm thấy bất kỳ cổng nào đang chạy máy chủ nhưng không được liệt kê trong / etc / dịch vụ, thì điều đó

dụ, LowPortScanner có thể cho bạn biết rằng có một máy chủ trêncổng 800, trong đó, khi điều tra thêm, hóa ra là một máy chủ HTTP

mà ai đó đang chạy để phục vụ các tệp MP3 và đang bão hòa T1 củabạn

Ba nhà xây dựng tạo ra các socket không được kết nối Chúng cungcấp nhiều quyền kiểm soát hơn đối với chính xác cách socket cơ bảnhoạt động, ví dụ bằng cách chọn một máy chủ proxy khác hoặc sơ đồ

mã hóa:

Trang 29

1.2.2 Xây dựng mà không cần kết nối

Tất cả các nhà xây dựng mà chúng ta đã nói đến cho đến nay đềutạo ra đối tượng socket và mở kết nối mạng với máy chủ từ xa Đôikhi bạn muốn chia nhỏ các hoạt động đó Nếu bạn không đưa ra đối

số cho trình xây dựng Socket, nó không có nơi nào để kết nối với:

Public socket()

Bạn có thể kết nối sau đó bằng cách chuyển SocketAddress đến mộttrong các phương pháp kết nối () Chẳng hạn:

Bạn có thể vượt qua một int là đối số thứ hai để chỉ định số mili giây

để chờ trước khi kết nối hết thời gian:

public void connect (SocketAddress endpoint, int timeout)

throws IOException

Mặc định, 0, có nghĩa là chờ đợi mãi mãi

Raison d'être cho nhà xây dựng này là để cho phép các loại socketkhác nhau Bạn cũng cần sử dụng nó để thiết lập một tùy chọn socketchỉ có thể được thay đổi trước khi socket kết nối Tôi sẽ thảo luận về

Trang 30

điều này trong "Thiết lập tùy chọn socket" trên trang 259 Tuy nhiên,lợi ích chính mà tôi tìm thấy là nó cho phép tôi dọn dẹp mã trong cáckhối cuối cùng, đặc biệt là trước Java 7 Các noargs constructor némkhông có ngoại lệ vì vậy nó cho phép bạn tránh kiểm tra null gâyphiền nhiễu khi đóng một socket trong một khối cuối cùng Vớitrình xây dựng ban đầu, hầu hết các mã trông như thế này:

Với nhà xây dựng mái vòm, nó trông như thế này:

Trang 31

Điều đó không hoàn toàn tốt đẹp như phiên bản autoclosing trongJava 7, nhưng nó là một cải tiến.

1.2.3 Địa chỉ socket

Lớp SocketAddress đại diện cho một điểm cuối kết nối Nó làmột lớp trừu tượng trống rỗng không có phương pháp nào ngoài mộttrình xây dựng mặc định Ít nhất về mặt lý thuyết, lớpSocketAddress có thể được sử dụng cho cả socket TCP và khôngTCP Trong thực tế, chỉ có socket TCP / IP hiện đang được hỗ trợ vàcác địa chỉ socket bạn thực sự sử dụng là tất cả các trường hợp củaInetSocketAddress

Mục đích chính của lớp SocketAddress là cung cấp một cửa hàngthuận tiện cho thông tin kết nối socket thoáng qua như địa chỉ IP vàcổng có thể được tái sử dụng để tạo socket mới, ngay cả sau khisocket ban đầu bị ngắt kết nối và thu gom rác Để đạt được điều này,lớp Socket cung cấp hai phương pháp trả về các đối tượngSocketAddress (getRemoteSocketAddress() trả về địa chỉ của hệthống được kết nối và getLocalSocketAddress() trả về địa chỉ mà từ

đó kết nối được thực hiện):

Socket socket = new Socket("www.yahoo.com", 80);

SocketAddress yahoo = socket.getRemoteSocketAddress();

socket.close();

Sau đó, bạn có thể kết nối lại với Yahoo! bằng địa chỉ này:

Socket socket2 = new Socket();

socket2.connect(yahoo);

Trang 32

Lớp InetSocketAddress (là lớp con duy nhất của SocketAddress trongJDK và là lớp con duy nhất tôi từng gặp) thường được tạo bằng máychủ và cổng (dành cho khách hàng) hoặc chỉ là cổng (đối với máy chủ):

public InetSocketAddress(InetAddress address, int port)

public InetSocketAddress(String host, int port)

Bạn cũng có thể sử dụng phương pháp nhà máy tĩnhInetSocketAddress.createUnresolved() để bỏ qua việc tra cứu máychủ trong DNS:

public static InetSocketAddress createUnresolved(String host, int port)

InetSocketAddress có một vài phương pháp getter bạn có thể sửdụng để kiểm tra đối tượng:

public final InetAddress getAddress()

public final int getPort()

public final String getHostName()

1.2.4 Máy chủ Proxy

Trình xây dựng cuối cùng tạo ra một socket không được kết nối kếtnối thông qua một máy chủ proxy được chỉ định:

Public socket(Proxy proxy)

Thông thường, máy chủ proxy mà socket sử dụng được điều khiểnbởi các thuộc tính hệ thống socksProxyHost và socksProxyPort , vàcác thuộc tính này áp dụng cho tất cả các socket trong hệ thống Tuynhiên, một socket được tạo bởi trình xây dựng này sẽ sử dụng máychủ proxy được chỉ định thay thế Đáng chú ý nhất, bạn có thể vượtqua Proxy.NO_PROXY cho đối số để bỏ qua tất cả các máy chủproxy hoàn toàn và kết nối trực tiếp với máy chủ từ xa Tất nhiên,nếu tường lửa ngăn chặn các kết nối trực tiếp, Java không thể làm gì

về nó; Và kết nối sẽ thất bại

Trang 33

Để sử dụng một máy chủ proxy cụ thể, hãy chỉ định nó theo địa chỉ.

Ví dụ: đoạn mã này sử dụng máy chủ proxy SOCKS tại

myproxy.example.com để kết nối với máy chủ login.ibiblio.org:

Trang 34

SOCKS là loại proxy cấp thấp duy nhất mà Java hiểu được Ngoài racòn có Proxy.Type.HTTP cấp cao hoạt động trong lớp ứng dụngthay vì lớp vận chuyển và Proxy.Type.DIRECT đại diện cho các kếtnối không proxy.

Trang 35

1.3 Nhận thông tin về socket

Các đối tượng socket có một số thuộc tính có thể truy cập thông quacác phương pháp getter:

• Địa chỉ từ xa

• Cổng từ xa

• Địa chỉ địa phương

• Cảng địa phương

Dưới đây là các phương pháp getter để truy cập các thuộc tính này:

Không có phương pháp setter Các thuộc tính này được thiết lậpngay khi socket kết nối và được cố định từ đó trở đi

Các phương thức getInetAddress() và getPort() cho bạn biết máychủ từ xa và cổng socket được kết nối; hoặc, nếu kết nối hiện đãđóng, máy chủ và cổng nào socket được kết nối khi nó được kết nối.Các phương pháp getLocalAddress() và getLo calPort() cho bạnbiết giao diện mạng và cổng mà Socket được kết nối từ đó

Không giống như cổng từ xa, (đối với socket khách hàng) thường làmột "cổng nổi tiếng" đã được ký trước bởi một ủy ban tiêu chuẩn,cổng địa phương thường được hệ thống lựa chọn vào thời gian chạy

từ các cổng không sử dụng có sẵn Bằng cách này, nhiều khách hàngkhác nhau trên một hệ thống có thể truy cập cùng một dịch vụ cùngmột lúc Cổng cục bộ được nhúng trong các gói IP ra nước ngoàicùng với địa chỉ IP của máy chủ cục bộ, vì vậy máy chủ có thể gửi

dữ liệu trở lại cổng bên phải trên máy khách

Ví dụ 8-6 đọc một danh sách các tên máy chủ từ dòng lệnh, cố gắng

mở một socket cho mỗi cái, và sau đó sử dụng bốn phương pháp này

Trang 36

để in máy chủ từ xa, cổng từ xa, địa chỉ địa phương và cổng địaphương.

Ví dụ 8-6 Lấy thông tin của socket

Đây là kết quả của một cuộc chạy mẫu Tôi đã bao gồm

www.oreilly.com trên đường dây chỉ huy hai lần để chứng minh rằng

mỗi kết nối được gán một cổng địa phương khác nhau, bất kể máychủ từ xa; cổng cục bộ được gán cho bất kỳ kết nối nào là không thểđoán trước và phụ thuộc chủ yếu vào những cổng khác đang được sử

dụng Kết nối với login.ibiblio.org thất bại vì máy đó không chạy bất

kỳ máy chủ nào trên cổng 80:

Trang 37

1.3.1 Đã đóng hoặc Đã kết nối?

Phương pháp isClosed() trả về đúng nếu socket được đóng, sai nếukhông Nếu bạn không chắc chắn về trạng thái của socket, bạn có thểkiểm tra nó bằng phương pháp này thay vì mạo hiểm ioexception.Chẳng hạn:

if (socket.isClosed()) { // do something

} else { // do something else

}

Tuy nhiên, đây không phải là một bài kiểm tra hoàn hảo Nếu socketchưa bao giờ được kết nối ngay từ đầu, isClosed () trả về sai, mặc dùsocket không chính xác mở

Lớp Socket cũng có phương pháp isConnected() Cái tên hơi gâyhiểu lầm Nó không cho bạn biết nếu socket hiện đang được kết nốivới một máy chủ từ xa (như nếu nó là UNCLOSED) Thay vào đó,

nó cho bạn biết liệu socket đã từng được kết nối với máy chủ từ xahay chưa Nếu socket có thể kết nối với máy chủ từ xa, phương phápnày sẽ trở thành sự thật, ngay cả sau khi socket đó đã được đóng lại

Để biết nếu một socket hiện đang mở, bạn cần kiểm tra xemisConnected () trả về đúng và isClosed() trả về sai Chẳng hạn:

boolean connected = socket.isConnected() && !socket.isClosed();

Cuối cùng, phương pháp isBound () cho bạn biết liệu socket có bịràng buộc thành công với cổng đi trên hệ thống địa phương haykhông Trong khi isConnected() đề cập đến đầu từ xa của socket,isBound() đề cập đến kết thúc cục bộ Điều này vẫn chưa quantrọng lắm Ràng buộc sẽ trở nên quan trọng hơn khi chúng ta thảoluận về các socket máy chủ trong Chương 9

Trang 39

1.4 Tùy chọn cài đặt socket

Tùy chọn socket chỉ định cách các socket gốc mà lớp Java Socketdựa vào gửi và nhận dữ liệu Java hỗ trợ chín tùy chọn cho socketphía máy khách:

bộ đệm."

1.5 Ngoại lệ socket

public class SocketException extends IOException

Tuy nhiên, biết rằng một vấn đề xảy ra thường không đủ để giảiquyết vấn đề Máy chủ từ xa có từ chối kết nối vì nó bận không? Cóphải máy chủ từ xa từ chối kết nối vì không có dịch vụ nào nghe trêncổng? Kết nối đã cố gắng hết thời gian chờ vì tắc nghẽn mạng hoặc

vì máy chủ đã ngừng hoạt động? Có một số phân lớp củaSocketException cung cấp thêm thông tin về những gì đã xảy ra vàtại sao:

Trang 40

BindException được ném nếu bạn cố gắng xây dựng một đối tượngSocket hoặc ServerSocket trên một cổng cục bộ đang được sử dụnghoặc bạn không có đủ đặc quyền để sử dụng Một ConnectException được ném khi một kết nối bị từ chối tại máy chủ từ xa,điều này thường xảy ra vì máy chủ bận rộn hoặc không có quy trìnhnào đang nghe trên cổng đó Cuối cùng, mộtNoRouteToHostException chỉ ra rằng kết nối đã hết thời gian.

Gói java.net cũng bao gồm ProtocolException, một lớp con trực tiếpcủa IOException:

public class ProtocolException extends IOException

Điều này được ném khi dữ liệu được nhận từ mạng bằng cách nào

đó vi phạm đặc điểm kỹ thuật TCP / IP

Không có lớp ngoại lệ nào trong số này có bất kỳ phương pháp đặcbiệt nào bạn sẽ không tìm thấy trong bất kỳ lớp ngoại lệ nào khác,nhưng bạn có thể tận dụng các lớp con này để cung cấp thêm thôngbáo lỗi thông tin hoặc để quyết định xem việc thử lại hoạt động viphạm có khả năng thành công hay không

1.6 Socket trong ứng dụng GUI

Trình duyệt web HotJava là máy khách mạng Java GUI quy mô lớnđầu tiên HotJava đã ngừng hoạt động, nhưng vẫn còn nhiều ứngdụng khách nhận thức được mạng được viết bằng Java, bao gồmEclipse IDE và máy khách Frostwire BitTorrent Hoàn toàn có thểviết các ứng dụng khách hàng chất lượng thương mại trong Java; vàđặc biệt có thể viết các ứng dụng nhận thức mạng, cả khách hàng vàmáy chủ Phần này thể hiện một khách hàng mạng, whois, để minhhọa cho điểm này; và thảo luận về những cân nhắc đặc biệt phát sinhkhi tích hợp mã mạng với các ứng dụng Swing Ví dụ dừng lại ngắn

Ngày đăng: 05/12/2022, 15:22

HÌNH ẢNH LIÊN QUAN

Đầu ra điển hình giống như nếu bạn kết nối với Telnet: $ java DaytimeClient - BÁO CÁO CHI TIẾT LẬP TRÌNH MẠNG đề tài SOCKET FOR CLIENTS SOCKET FOR SERVERS
u ra điển hình giống như nếu bạn kết nối với Telnet: $ java DaytimeClient (Trang 13)
Hình 8-1 cho thấy một giao diện có thể cho một máy khách whois - BÁO CÁO CHI TIẾT LẬP TRÌNH MẠNG đề tài SOCKET FOR CLIENTS SOCKET FOR SERVERS
Hình 8 1 cho thấy một giao diện có thể cho một máy khách whois (Trang 48)

🧩 Sản phẩm bạn có thể quan tâm

w