phan 1 sv

169
Buổi 1 LẬP TRÌNH MẠNG CĂN BẢN Hồng Nghi - MMT

Upload: chaunguyen83

Post on 04-Jul-2015

484 views

Category:

Education


2 download

TRANSCRIPT

Page 1: Phan 1   sv

Buổi 1

LẬP TRÌNH MẠNG CĂN BẢN

Hồng Nghi - MMT

Page 2: Phan 1   sv

Nguồn Tham khảo

2

Network programming in NET with CSharp and VB.NET, Fiach Reid, Digital Press, 2004

C# Network Programming, Richard Blum, Sybex, 2003

Slide bài giảng lập trình mạng căn bản của Thầy Trần Bá Nhiệm – Khoa MMT&TT

Và một số trang Web khác

Page 3: Phan 1   sv

Mục tiêu

3

Cung cấp các kiến thức cơ bản về lập trình ứng dụng mạng

– Xây dựng ứng dụng Server.

– Xây dựng ứng dụng Client.

– Các kỹ thuật vào ra.

Cung cấp các kỹ năng cần thiết để thiết kế và xây dựng ứng dụng mạng

– Sử dụng thư viện, môi trường, tài liệu.

– Thiết kế, xây dựng chương trình

Page 4: Phan 1   sv

Tổng quan về mạng máy tính

4

Page 5: Phan 1   sv

Mô hình OSI

5

Được tổ chức tiêu chuẩn hóa ISO đưa ra nhằm cung cấp 1 mô hình chuẩn cho các nhà sản xuất và cung cấp sản phẩm viễn thông.

Ý tưởng mô hình hóa tạo ra hỗ trợ cho việc kết nối giữa các hệ thống và modun hóa các thành phần phục vụ mạng viễn thông

Page 6: Phan 1   sv

Mô hình OSI (Open Systems

Interconnection )

6

Tầng ứng dụng (Application layer): cung cấp các phương tiện cho người sử dụng sử dụng các dịch vụ của mạng.

Tầng trình bày (Presentation layer): quy định biểu diễn dữ liệu.

Tầng phiên (Session layer): quản lý các phiên của ứng dụng.

Tầng vận chuyển (Transport layer): quy định kết nối end-to-end .

Tầng mạng (Network layer): quy định địa chỉ mạng, định tuyến, truyền dữ liệu.

Tầng liên kết (Data link layer): điều khiển kết nối, truy xuất đường truyền.

Tầng vật lý (Physical layer): đường truyền vật lý, các chuẩn về điện, dây cáp, đầu nối..

Page 7: Phan 1   sv

Mô hình TCP/IP(Internet control

message protocol)

7

Application: cung cấp các dịch vụ cho các

ứng dụng mạng

FTP, SMTP, HTTP

Transport: truyền dữ liệu giữa các tiến trình

TCP, UDP

Network: dẫn đường cho các gói tin từ nguồn

đến đích

IP, các giao thức dẫn đường

Link: truyền dữ liệu giữa các trạm lân cận

PPP, Ethernet

Physical: các bit “trên đường dây”

Page 8: Phan 1   sv

Các họ giao thức

8

Page 9: Phan 1   sv

Giao thức TCP

9

Hướng kết nối: connection orientedHai bên phải thiết lập kênh truyền trước khi truyền

dữ liệu.

Được thực hiện bởi quá trình gọi là bắt tay ba bước (three ways handshake).

• Truyền dữ liệu theo dòng (stream oriented): tự động phân chia dòng dữ liệu thành các đoạn nhỏ để truyền đi, tự động ghép các đoạn nhỏ thành dòng dữ liệu và gửi trả ứng dụng.

• Đúng trật tự (ordering guarantee): dữ liệu gửi trước sẽ được nhận trước

Page 10: Phan 1   sv

Giao thức TCP

10

Đặc tính của TCP Tin cậy, chính xác: thông tin gửi đi sẽ được đảm bảo đến đích, không

dư thừa, sai sót...Độ trễ lớn, khó đáp ứng được tính thời gian thực.

Page 11: Phan 1   sv

Cổng giao thức

11

Mỗi máy tính có nhiều ứng dụng chạy đồng thời.

Dữ liệu có kèm theo thông tin cho biết ai đang sử dụng nó

Dùng để phân biệt 2 ứng dụng mạng với nhau đi kèm với IP và Socket

Nằm trong khoảng 1…65535.

Page 12: Phan 1   sv

Giao thức UDP

12

Giao thức UDP: User Datagram ProtocolCũng là giao thức lõi trong TCP/IP.

Cung cấp dịch vụ truyền dữ liệu giữa các ứng dụng.

UDP chia nhỏ dữ liệu ra thành các datagram

Sử dụng trong các ứng dụng khắt khe về mặt thời gian, chấp nhận sai sót: thoại, video, game...

• Đặc tính của UDPKhông cần thiết lập kết nối trước khi truyền (Connectionless).

Nhanh, chiếm ít tài nguyên dễ xử lý.

Hạn chế: Không có cơ chế báo gửi (report).

Không đảm báo trật tự các datagram (ordering).

Không phát hiện được mất mát hoặc trùng lặp thông tin (loss, duplication).

Page 13: Phan 1   sv

UDP header

13

Page 14: Phan 1   sv

Cổng giao thức

14

Page 15: Phan 1   sv

Địa chỉ Ip và các lớp dành riêng

15

Mỗi máy tính kết nối vào internet phải có 1 địa chỉ IP.

Địa chỉ 127.0.0.1 là địa chỉ loopback.

Địa chỉ IP của 1 máy có thể được cấp bởi DHCP server .

Page 16: Phan 1   sv

Địa chỉ mạng

16

Page 17: Phan 1   sv

Địa chỉ broadcast

17

Page 18: Phan 1   sv

Hệ thống phân giản tên miền DNS

18

Các tên miền được phân cấp và quản lý bởi INTERNIC

Cấp cao nhất là ROOT, sau đó là cấp 1, cấp 2,...

Page 19: Phan 1   sv

Tổng quan về lập trình mạng

19

Page 20: Phan 1   sv

Sơ lược về lập trình mạng

20

Lập trình mạng là các kỹ thuật lập trình nhằm xây dựng ứng dụng, phần mềm khai thác hiệu quả tài nguyên mạng máy tính.

Ngôn ngữ lập trình mạngC/C++: Mạnh và phổ biến, được hầu hết các lập trình

viên sử dụng để viết các ứng dụng mạng hiệu năng cao.Java: Khá thông dụng, sử dụng nhiều trong các điện

thoại di động (J2ME).C#: Mạnh và dễ sử dụng, tuy nhiên chạy trên nền .Net

Framework và chỉ hỗ trợ họ hệ điều hành Windows.Python, Perl, PHP...Ngôn ngữ thông dịch, sử dụng để

viết các tiện ích nhỏ, nhanh chóngGiáo trình này sẽ chỉ đề cập đến hai ngôn ngữ C/C++và

C#.

Page 21: Phan 1   sv

Thư viện lập trình mạng

21

Windows SocketAPI ( WinSock) Thư viện liên kết động (WS2_32.DLL) đi kèm trong hệ điều hành

Windows của Microsoft. Thường sử dụng cùng với C/C++. Cho hiệu năng cao nhất.

System.Net và System.Net.Sockets Hai namespace trong bộ thư viện .NET của Microsoft Dễ sử dụng Thường sử dụng với C#

• MFC SocketNằm trong bộ thư viện MFC của MicrosoftĐóng gói các hàm của WinSock dưới dạng các lớp hướng đối tượng.Dễ sử dụng và hiệu năng cao.

• Các thư viện của các ngôn ngữ khác: Java, PHP, Python...

• Thư viện sử dụng trong giáo trình: WinSock, MFC Socket, System.Net và System.Net.Sockets

Page 22: Phan 1   sv

Công cụ lập trình

22

Visual Studio (6.0, 2003 .NET, 2005, 2008, 2010, 2013)

Rất mạnh

Hỗ trợ cả WinSock, MFC Socket và .NET Socket (Phiênbản 2003.NET trở lên).

Dev C++

Miễn phí

Chỉ hỗ trợ WinSock

Page 23: Phan 1   sv

Công cụ hỗ trợ

23

TCPView: Hiển thị các kết nối hiện tại của máy tính.

Resource Monitor: ~ TCPView.

Wireshark.

Netcat

Page 24: Phan 1   sv

.NET FrameWork

24

Không phải là NNLT

Cung cấp framework cho 4 ngôn ngữ lập trìnhlàm việc với nhau gồm C#, VB.Net, Managed C++, J# .Net

Định nghĩa FrameWork Class Library(FCL)

Comman Laguage Runtime (CRL) là một máy ảođược thiết kết riêng cho Windows, là môi trườngthực thi cho các ứng dụng.

Các ngôn ngữ trong .Net có khả năng làm việchợp tác với nhau rất tốt.Vd: Class đã biên dịchtrong c# dùng được trong VB.Net

Page 25: Phan 1   sv

.NET FrameWork

25

Gồm có 3 thành phần: Các ngôn ngữ lập trình

Thư viện các lớp (Framework Class Library - FCL)

The Common Language Runtime (CLR)

.NET dùng trình biên dịch Just-in-time (JIT).

Mọi lớp trong .NET đều kế thừa từSystem.Object

2 ngôn ngữ phổ biến nhất là VC# và VB.NET

Không hỗ trợ đa kế thừa

Page 26: Phan 1   sv

Microsoft Intermediate Language(MSIL)

26

Các ứng dụng phát triển trên nền .NET Framework, sau khi biên dịch, không được dịch ra ngôn ngữ máy mà được biên dịch sang một ngôn ngữ có tên là: Microsoft Intermediate Language (MSIL)

Page 27: Phan 1   sv

Common Language Runtime

27

Sau khi biên dịch lần đầu tiên chạy chương trình, ngôn ngữ MSIL sẽ được biên dịch sang ngôn ngữ máy.

Quá trình chuyển đổi từ MSIL sang ngôn ngữ máy lúc thực thi chương trình được thực hiện bởi thành phần Just – in – time compiler nằm trong CLR (Common Language Runtime).

Page 28: Phan 1   sv

Các thành phần chính của Visual Studio

28

Page 29: Phan 1   sv

Biến và qui tắc đặt tên biến

29

Biến là đại lượng dùng để chứa dữ liệu.

Ví dụ bạn muốn nhập tuổi của một người từ bàn phím vào trong chương trình, khi đó trong chương trình của bạn phải có một biến để chứa tuổi của người đó.

Cú pháp khai báo biến:

<Kiểu dữ liệu> Tên biến;

Hoặc vừa khai báo biến vừa khỏi tạo giá trị

<Kiểu dữ liệu> Tên biến = giá trị ;

Mỗi một biến được cấp phát một vùng nhớ, kích thước của vùng nhớ phụ thuộc vào kiểu dữ liệu của biến, và vùng nhớ đó có một địa chỉ xác định.

Qui tắc đặt tên biến: Tên biến không được trùng với tên từ khóa Không được đặt tên biến bắt đầu bằng kí số Ngôn ngữ C# phân biệt chữ hoa và chữ thường.

Page 30: Phan 1   sv

Kiểu dữ liệu

30

Page 31: Phan 1   sv

Hướng đối tượng trong C#

31

Namespace, lớp, đối tượng

Construtors và Destructors

Nạp chồng phương thức( Overloading)

Các phương thức chồng toán tử( Operator Overloading)

Ghi đè (Overriding)

Kế thừa( Inheritance)

Page 32: Phan 1   sv

Namespace

32

Dùng để quản lý, tránh đặt trùng tên lớp

Giảm bớt sự phức tạp khi chạy cùng các ứng dụng khác

Có thể khai báo các namespace bên trong các namespace khác

Ví dụ:namespace NameSpace{// khai báo các lớp

public classA{}public classB{}

}

namespace NameSpace{// khai báo các lớp

public classA{}namespace NameSpace{

//……}

}

Page 33: Phan 1   sv

Lớp và đối tượng

33

Một kiểu trong C# định nghĩa bằng từ khoá class (và được gọi là lớp) còn thể hiện của lớp được gọi là đối tượng.

Khai báo :class Tên_lớp{//khai báo các thành phần… }

• Ví dụ:

class Sinhvien{

private string mMSSV;private string mHoten; public void In(){….}

}

Page 34: Phan 1   sv

Phương thức

34

Các phương thức định nghĩa những gì mà một lớp có thể làm

1 phương thức là một hàmVí dụ:

class QLSV{ public void IntenSinhvien(

) { // thực hiện 1 công việc

gì đóSinhvien sv = new

Sinhvien();sv.In();

} }

class Sinhvien{

private string mMSSV;private string mHoten; public void In(){….}

}

Page 35: Phan 1   sv

Constructors(Hàm khởi tạo)

35

Được gọi khi đối gọi tới đối tượng được tạo

Dùng để khởi tạo đối tượng

Có cùng tên với tên lớp

Có thể có hoặc không có tham số, và không có giá trị trả về

class Sinhvien{

private string mMSSV;private string mHoten; public Sinhvien(){

mMSSV = “DH1111048”;mHoten = “Nguyễn Văn A”;

} public Sinhvien(string mssv, string hoten){

mMSSV = mssv;mHoten = hoten;

}

}

Page 36: Phan 1   sv

Destructors( Hàm hủy)

36

Hàm hủy là một hàm thành viên được gọi tự động khi đối tượngbị hủy.

Ta không thể gọi trực tiếp, bộ biên dịch kích phát lời gọi đếnhàm hủy khi một đối tượng vượt ra ngoài phạm vi.

Có cùng tên với tên lớp nhưng có thêm dấu ~ phía trước.

class username(){

public:

~username();

};

Không có kiểu trả về, không có đối số.

Page 37: Phan 1   sv

Destructors

37

Gọi tự động khi đối tượng được hủy

class Sinhvien{

private string mMSSV;private string mHoten; public Sinhvien(){

mMSSV = “DH1111048”;mHoten = “Nguyễn Văn A”;

} ~Sinhvien(){

// thực hiện thao tác}

}

Page 38: Phan 1   sv

Phương thức Overloading

38

Các phương thức có cùng tên, nhưng khác:

Giá trị trả về

Tham số truyền

Kiểu tham số truyền

class Sinhvien{

private string mMSSV;private string mHoten; public In(){//…

} public In(string mssv){//….

}

}

Page 39: Phan 1   sv

Phương thức Overriding

39

Lng.

Đ, có

i “ nh vi.

(Base class (Derived class

Page 40: Phan 1   sv

Inheritance(kế thừa)

40

Các lớp với các đặc điểm tương tự nhau có thể được tổ chức thành một sơ đồ phân cấp kế thừa.

Cho phép tạo ra 1 lớp có thuộc tính và phươngthức (kế thừa) của 1 lớp khác. Sau đó xây dựngnhững thuộc tính và phương thức riêng.

Tạo khả năng xây dựng lớp mới từ lớp đã có

Lớp cha trong kế thừa gọi là lớp cơ sở (base class)

Lớp con trong kế thừa gọi là lớp dẫn xuất(derived class)

Page 41: Phan 1   sv

Inheritance(kế thừa)

41

Page 42: Phan 1   sv

Inheritance(kế thừa)

42

class TênLớpCon : TênLớpCha

{ // Thân lớp con

}

Hoặc

class TênLớpDẫnXuất : TênLớ pCơSở

{ // Thân lớp dẫ n xuấ t

}

Page 43: Phan 1   sv

Inheritance(kế thừa)

43

// Lớp cơ sở Point2D

class Point2D

{ public int x,y;public void Xuat2D() {

Console.WriteLine("({0}, {1} )", x, y);}

}

// Lop dan xuat Point3D ke thua tu lop Point2D

class Point3D:Point2D

{ public int z;public void Xuat3D() {

Console.WriteLine("({0}, {1} , {2})", x, y, z);}

}

Page 44: Phan 1   sv

Polymorphism(Tính đa hình )

44

Đa hình thái, nhiều cách phản ứng khác nhau cho cùng một hành vi

Lớp A có hành vi M()

Lớp B là con của lớp A, trong lớp B viết lại hành viM()

Có biến đối tượng obj

Tại thời điểm t1: obj chỉ đến một thực thể A, obj.M() sẽ cho một phản ứng

Tại thời điểm t2: obj chỉ đến một thực thể B, obj.M() sẽ cho một phản ứng khác

Tính đa hình có được là nhờ kỹ thuật override hành vi giữa 2 lớp cha con.

Page 45: Phan 1   sv

Từ khóa private và public

45

Page 46: Phan 1   sv

Delegate và Event

46

Trong lập trình đôi lúc gặp tình huống phải thực thi một hành động nào đó, nhưng lại không biết sẽ gọi phương thức nào của đối tượng nào.

Về mặt kỹ thuật, delegate thuộc kiểu tham chiếu được dùng để đóng gói phương thức đã xác định kiểu trả về và số lượng, kiểu tham số.

Vd: public delegate int WhichIsFirst(object obj1, object obj2)

Page 47: Phan 1   sv

I/O trong .NET

47

Page 48: Phan 1   sv

Streams

48

Hai stream quan trọng: networkStream và fileStream

Có 2 cách sử dụng: đồng bộ và bất đồng bộ

Việc chờ 1 tác vụ hoàn thành rồi thực hiện 1 tác vụ khác gây ra một số vấn đề bất tiện.

Bằng cách dùng phương thức gọi đồng bộ tạo được hiệu quả máy tính có thể làm nhiều việc cùng lúc nhưng thực chất là do việc chuyển những tác vụ trong khoảng 1 vài mili giây( Các máy tính hầu như chỉ có 1 CPU)

Page 49: Phan 1   sv

Streams với files

49

Tạo ra một ứng dụng trong .NET với những thành phần như sau:

Một form

Một File Open Dialog control tên openFileDialog

Một textbox tên tbResults, đặt thuộc tính multiline=true.

Hai buttons tên btnReadAsync và btnReadSyn

• Sử dụngng namespace: using System.IO

Page 50: Phan 1   sv

Streams với files

50

Khai báo:FileStream fs;byte[] fileContents;AsyncCallback callback;delegate void InfoMessageDel(String info); Khai báo thêm phương thức InfoMessageDel để tránh các thread

tranh chấp tham chiếu đến 1 đối tượng.

• Thêm code xử lý sự kiện click đối tượng btnReadAsync:private void btnReadAsync_Click(object sender, EventArgs e){

openFileDialog.ShowDialog();callback = new AsyncCallback(fs_StateChanged);fs = new FileStream(openFileDialog.FileName, FileMode.Open,FileAccess.Read, FileShare.Read, 4096, true);fileContents = new Byte[fs.Length];fs.BeginRead(fileContents, 0, (int)fs.Length, callback, null);

}

Page 51: Phan 1   sv

Streams với files

51

Nội dung hàm fs_StateChanged:private void fs_StateChanged(IAsyncResult asyncResult)

{

if (asyncResult.IsCompleted){

string s = Encoding.UTF8.GetString (fileContents);

InfoMessage(s);fs.Close();

}

} Code xử lý sự kiện của btnReadSync :

private voibtnReadSync_Click( object sender, EventArgs e)

{

openFileDialog.ShowDialog();

Thread thdSyncRead = new

Thread(new ThreadStart(syncRead));

thdSyncRead.Start();

}

Page 52: Phan 1   sv

Streams với files

52

public void syncRead()

{

FileStream fs;

try

{

fs = newFileStream(openFileDialog.FileName, FileMode.OpenOrCreate);

}

catch (Exception ex)

{

MessageBox.Show(ex.Message);

return;

}

…..

Tiếp theo try..catch

fs.Seek(0, SeekOrigin.Begin);

byte[] fileContents = new byte[fs.Length];

fs.Read(fileContents, 0, (int)fs.Length);

string s = Encoding.UTF8.GetString(fileContents);

InfoMessage(s);

fs.Close();

}

Page 53: Phan 1   sv

FileStream

53

Page 54: Phan 1   sv

Mã hóa dữ liệu

54

Trong ví dụ ở trên Encoding.UTF8.GetString() nhằm chuyển mảng byte thành string.

Các dạng khác Unicode (Encoding.Unicode), ASCII, UTF7.

UTF8 dùng 1 byte cho một ký tự, unicode dùng 2byte cho mỗi ký tự.

Page 55: Phan 1   sv

Binary và text streams

55

Plain text là 1 kiểu thông dụng cho người dùng dễ sử dụng, dễ đọc, dễ soạn thảo.

Tương lai sẽ thay bằng xml

Viết ứng dụng đếm số dòng có trong 1 file .txt

Page 56: Phan 1   sv

Binary và text streams

56

private void button1_Click(object sender, EventArgs e)

{

OpenFileDialog ofd = new OpenFileDialog();

ofd.ShowDialog();

FileStream fs = new FileStream(ofd.FileName, FileMode.OpenOrCreate);

StreamReader sr = new StreamReader(fs);

int lineCount = 0;

while (sr.ReadLine() != null)

{

lineCount++;

}

fs.Close();

MessageBox.Show("Có " + lineCount + " dòng " + ofd.FileName);

}

Page 57: Phan 1   sv

StreamReader

57

Page 58: Phan 1   sv

BinaryWriter

58

Page 59: Phan 1   sv

Serialize và Deserialize

59

BinaryFormatter sử dụng 2 phương thức

Serialize và Deserialize để viết và đọc đối tượng

từ trong luồng:

Serialize:chuyển đổi một đối tượng sang một

định dạng, và có thể được viết vào File mà không

mất dữ liệu.

Deserialize: đọc dữ liệu đã định dạng từ một

File và chuyển nó về dạng ban đầu.

Page 60: Phan 1   sv

Serialization

60

Serialization là một quá trình để chuyển đổi một cấu trúc dữ liệu hoặc đối tượng thành một định dạng có thể lưu trữ được (ví dụ như trong một file, bộ nhớ, hoặc vận chuyển thông qua mạng), sau đó nó có thể được phục hồi để trở lại trạng thái ban đầu trong một môi trường khác thông qua quá trình deserialization. Rất nhiều ngôn ngữ lập trình hiện nay hỗ trợ kĩ thuật này bao gồm C#, Java, Objective-C, Perl, Python, Ruby, PHP

Page 61: Phan 1   sv

Attribute [Serializable] và [NonSerialized]

61

Mọi đối tượng muốn được serialize đều phải được khai báo kèm theo attribute [Serializable]. Ngoài ra, mọi kiểu dữ liệu được sử dụng trong đối tượng cũng phải tuân theo quy tắc này.

Nếu bạn muốn loại trừ một thành phần (method, field, property,…) không muốn được serialize, bạn có thể đánh dấu chúng bằng attribute [NonSerialized].

Page 62: Phan 1   sv

Serialization

62

Ví dụ điển hình là hệ thống đặt hàng, vốn có yêucầu độ an toàn rất cao, vì vậy mỗi lỗi xảy ra phảiđược theo vết chặt chẽ

Để đặt đơn hàng vào stream (trên đĩa hoặc trênmạng) ta có thể ghi mỗi giá trị dưới dạng text, dùng ký tự phân cách,… để xuất và tái tạo cácđối tượng. Tuy nhiên cách dễ dàng nhất là dùngSerialization

Page 63: Phan 1   sv

Serialization

63

public enum purchaseOrderStates

{ISSUED,DELIVERED,INVOICED,PAID

}

[Serializable()] public class company

{public string name; public string address;public string phone;

}

[Serializable()]

Page 64: Phan 1   sv

Serialization

64

public class lineItem

{

public string description;

public int quantity;

public double cost;

}

[Serializable()]

public class purchaseOrder

{

private purchaseOrderStates _purchaseOrderStatus;

private DateTime _issuanceDate;

private DateTime _deliveryDate;

private DateTime _invoiceDate;

private DateTime _paymentDate;

public company buyer;

public company vendor;

public string reference;

public lineItem[] items;

Page 65: Phan 1   sv

Serialization

65

Serialization

public purchaseOrder()

{

_purchaseOrderStatus = purchaseOrderStates.ISSUED;

_issuanceDate = DateTime.Now;

}

public void recordDelivery()

{

if (_purchaseOrderStatus == purchaseOrderStates.ISSUED)

{

_purchaseOrderStatus = purchaseOrderStates.DELIVERED; _deliveryDate = DateTime.Now;

}

}

Page 66: Phan 1   sv

Serialization với SoapFormatter

66

Serialize đối tượng thành định dạng XML để truyền tải thông tin giữa các ứng dụng qua mạng thông qua giao thức HTTP. Do là dạng văn bản nên dung lượng dữ liệu tạo ra sẽ nặng hơn so với BinaryFormatter.

Hỗ trợ trong( System.Runtime.Serialization.Formatters.Soap)

Page 67: Phan 1   sv

Serialization dùng SoapFormatter

67

company Vendor = new company();

company Buyer = new company();

lineItem Goods = new lineItem();

purchaseOrder po = new purchaseOrder();

Vendor.name = "Acme Inc.";

Buyer.name = "Wiley E. Coyote";

Goods.description = "anti-RoadRunner cannon";

Goods.quantity = 1;

Goods.cost = 599.99;

po.items = new lineItem[1];

po.items[0] = Goods;

po.buyer = Buyer;

po.vendor = Vendor;

SoapFormatter sf = new SoapFormatter();

FileStream fs = File.Create("..\\po.xml");

sf.Serialize(fs, po);

fs.Close();

Page 68: Phan 1   sv

Deserialization dùng SoapFormatter

68

SoapFormatter sf = new SoapFormatter(); FileStream fs = File.OpenRead("..\\po.xml");purchaseOrder po = (purchaseOrder)sf.Deserialize(fs);fs.Close();MessageBox.Show("Customer is " + po.buyer.name +

"\nVendor is " + po.vendor.name + ", phone is " + po.vendor.phone +"\nItem is " + po.items[0].description + " has quantity " +po.items[0].quantity.ToString() + ", has cost " + po.items[0].cost.ToString());

Page 69: Phan 1   sv

SoapFormatter

69

Simple Object Access Protocol (SOAP)

Page 70: Phan 1   sv

Serialization dùng BinaryFormatter

70

Định dạng của SOAP tương đối ấn tượng, tuy nhiên không gọn nhẹ nên khá tiêu tốn băng thông đường truyền

Trong trường hợp ấy, phương pháp khả thi hơn là BinaryFormatter company Vendor = new company(); company Buyer = new company(); lineItem Goods = new lineItem();//tương tự ví dụ SoapFormatterBinaryFormatter bf = new BinaryFormatter(); FileStream fs = File.Create("..\\po_bin.txt"); bf.Serialize(fs, po); fs.Close();MessageBox.Show("Serialize succesful!", "Info");

Page 71: Phan 1   sv

Deserialization dùng BinaryFormatter

71

BinaryFormatter bf = new BinaryFormatter();

FileStream fs = File.OpenRead("..\\po_bin.txt");

purchaseOrder po =(purchaseOrder)bf.Deserialize(fs);

fs.Close();

MessageBox.Show("Customer is " + po.buyer.name);

Page 72: Phan 1   sv

Kết quả minh họa BinaryFormatter

72

Page 73: Phan 1   sv

Serialization dùng XmlSerializer

73

company Vendor = new company(); company Buyer = new company();

lineItem Goods = new lineItem();

//tương tự ví dụ SoapFormatter

XmlSerializer xs = new

XmlSerializer(po.GetType());

FileStream fs = File.Create("..\\po1.xml");

xs.Serialize(fs, po);

fs.Close();

Page 74: Phan 1   sv

Deserialization dùng XmlSerializer

74

purchaseOrder po = new purchaseOrder();

XmlSerializer xs = new XmlSerializer(po.GetType());

FileStream fs = File.OpenRead("..\\po1.xml");

po = (purchaseOrder)xs.Deserialize(fs);

fs.Close();

MessageBox.Show("Customer is " + po.buyer.name

+ "\nVendor is " + po.vendor.name

+ ", phone is " + po.vendor.phone

+ "\nItem is " + po.items[0].description

+ " has quantity "

+ po.items[0].quantity.ToString()

+ ", has cost " + po.items[0].cost.ToString());

Page 75: Phan 1   sv

XmlSerializer

75

Page 76: Phan 1   sv

Kết quả minh họa XmlSerializer

76

Page 77: Phan 1   sv

XmlSerializer, BinaryFormatter ,SoapFormatter?

77

XmlSerializer dùng cho dịch vụ Web.

BinaryFormatter/SoapFormatter dùng choRemoting.

SoapFormatter dùng để tuần tự hóa 1 đối tượng thành SOAP.

BinaryFormatter dùng để tuần tự hóa 1 đối tượng thành dạng nhị phân.

XmlSerializer chỉ chuyển đổi các tính chất publiccòn BinaryFormatter/SoapFormatter chuyển đổi cả public lẫn private.

Page 78: Phan 1   sv

Sockets

78

Page 79: Phan 1   sv

Socket là gì

79

Là nền tảng của lập trình mạng

Là một đối tượng thể hiện truy cập mức thấp vào IP Stack

Có thể ở chế độ mở, đóng hoặc 1 số chế độ trung gian khác

Có thể gởi, nhận dữ liệu

Dữ liệu tổng quát được gởi từng khối( gọi là packet ) khoảng vài KB/ lần để tăng hiệu suất

Page 80: Phan 1   sv

Nhắc lại địa chỉ và cổng

80

Page 81: Phan 1   sv

Nguyên lý hoạt động của địa chỉ và cổng

81

Trong máy có rất nhiều ứng dụng muốn trao đổi với ứng dụng khác thông qua mạng

Mỗi máy tính chỉ có 1 đường truyền dữ liệu

VD: có 2 ứng dụng trên máy A muốn trao đổi với 2 ứng dụng trên máy B, vấn đề? Làm sao gởi đến đúng ứng dụng cần gởi?

Mỗi ứng dụng sẽ được gán 1 số hiệu port nằm trong khoảng từ 1…65535

Page 82: Phan 1   sv

Nguyên lý hoạt động của địa chỉ và cổng

82

Trên máy A:

Khi 1 ứng dụng trên máy A muốn gởi đến 1 ứng dụng trên máy B chỉ cần điền vào số hiệu port(Remote Port) vào gói tin cần gởi

Trên máy B:

Các ứng dụng chỉ việc kiểm tra số port trên mỗi gói

tin đến có trùng với số hiệu Port của mình hay

không (Local Port).

Nếu đúng thì nó sẽ xử lý

Page 83: Phan 1   sv

SOCKET

File mô tả để tham chiếu đến kết nối mạng được gọi là các Socket.

Đặc trưng của Socket:

Một kết nối mạng hay một đường ống dẫn để truyền tải dữ liệu.

Một kiểu truyền thông như stream hay datagram.

Giao tiếp qua Socket

83

Page 84: Phan 1   sv

SOCKET Socket phải được gắn vào một địa chỉ mạng và một port trên hệ thống.

Socket đã được gắn địa chỉ mạng và port, được dùng để gởi và nhận dữ

liệu trong mạng.

Trong .Net Framework lớp Socket hỗ trợ cho việc lập trình Socket.

Namespace System.Net.Sockets chứa các lớp giao tiếp với Winsock API.

Phương thức tạo lập Socket trong .Net Framework như sau:

Socket (AddressFamily, SocketType, ProtocolType)

AddressFamily: định nghĩa kiểu mạng địa chỉ trong mạng.

SocketType: định nghĩa kiểu dữ liệu kết nối (kiểu Socket)

ProtocolType: định nghĩa kiểu giao thức kết nối.

Ví dụ: Socket sk = Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

84

Page 85: Phan 1   sv

Giao thức phổ biến và Số hiệu Port

85

Page 86: Phan 1   sv

Một số quy định

86

Không bao giờ có 2 ứng dụng cùng port

Well-know: 1-1023 thường dùng cho những ứng dụng quan trọng trên hệ điều hành

1024 – 49151: Thường dùng cho người lập trình( nên dùng theo qui định)

49152 – 65535 (Dynamic): Dùng dự trữ

Page 87: Phan 1   sv

Các thuộc tính của socket

87

Domain : vùng giao tiếp của socket .

• Nếu socket hoạt động trên môi trường internet thì nó sẽ có giá trị là AF_INET (tức là hoạt động dựa theo chuẩn internet và dùng IP để xác định địa chỉ vật lý).

• Nếu socket hoạt động trên môi trường mạng cục bộ thì ta có thể dùng giao tiếp theo chuẩn : AF_UNIX (dùng đường dẫn và hệ thống file để đặt tên và xác định kết nối giữa hai hay nhiều ứng dụng . Trong môi trường Linux thì các thiết bị cũng được coi như hệ thống file đặc biệt và socket cũng được coi như vậy )

Page 88: Phan 1   sv

Các thuộc tính của socket

88

Kiểu socket type

SOCK_STREAM : tạo ra kết nối bền vững (kết nối dạng TCP ) . Kết nối này đảm bảo gói tin này đến đích an toàn và không bị mất mát , nhưng nó có nhược điểm là chậm và tốn nhiều tài nguyên.

SOCK_DGRAM : cách gửi nhận dữ liệu một chiều (kết nối UDP) , client gửi dữ liệu đi mà không cần biết là server có nhân đựơc dữ liệu hay không . Server khi nhận được dữ liệu cũng không cần phải xác nhận với client là đã nhận dữ liệu . Tuy không an toàn nhưng nó nhanh và được sử dụng nhiều trong môi trường multimedia.

Page 89: Phan 1   sv

Các thuộc tính của socket

89

Giao thức của socket (protocol ):

Giao thức là cách quy ước gửi nhận dữ liệu trong quá trình trao đổi thông tin (VD ai gửi trước , ai nhận , gửi nhận theo thứ tự nào ....) Có nhiều giao thức đối với mỗi loại socket , nhưng dùng nhiều là TCP và UDP .

Page 90: Phan 1   sv

MỘT SỐ HÀM THÔNG DỤNG CỦA SOCKET

90

Hàm tạo socket :SOCKET socket( int af, int type, int protocol);

af : domain . Có thể lấy các giá trị sau : AF_INET , AF_UNIX , AF_IPX , AF_ISO , AF_NS ...

type : SOCK_STREAM , SOCK_DGRAM

protocol : lấy giá trị 0 để sử protocol mặc định cho mỗi loại socket

Giá trị trả về là socket discriptor , là một con số dùng để mô tả socket mình vừa tạo ra .

Page 91: Phan 1   sv

MỘT SỐ HÀM THÔNG DỤNG CỦA SOCKET

91

Hàm đóng socket :closesocket(SOCKET sk ) ;

Hàm bindint bind(SOCKET s, const struct sockaddr* name, int namelen);Trước khi gọi hàm bind bạn phải tạo một socket trước bằng hàm socket() . Sau khi tạo socket là tới lúc mình sẽ dùng hàm bind gán cho nó các thông tin như port và địa chỉ

Page 92: Phan 1   sv

Hàm accept

92

Khi ta gọi hàm accept nó sẽ đưa thread mà hàm accept đang hoạt động vào trạng thái blocking . Khi có một kết nối ở trong hàng đợi thì hàm accept sẽ kết thúc và thread sẽ thoát khỏi trạng thái blocking . Khi này hàm accept đã tạo ra một socket mới ( thông tin về socket này chúng ta không thể biết ) và đặt các địa chỉ của client vào struct sockaddr* addr . Socket mới này chính là kết quả trả về của hàm accept . Ta sẽ dùng socket mới này để liên lạc với client chứ không dùng socket cũ là s .

Page 93: Phan 1   sv

Các hàm send và recv

93

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

• int recv( SOCKET s, char* buf, int len, int flags);

Đây là các hàm dùng để trao đổi thông tin giữa client và server (dạng kết nối TCP )int recvfrom( SOCKET s, char* buf, int len, int flags, struct sockaddr* from, int* fromlen);int sendto( SOCKET s, const char* buf, int len, int flags, const struct sockaddr* to, int tolen);Đây là các hàm dùng để trao đổi thông tin giữa client và server (dạng kết nối UDP )

Page 94: Phan 1   sv

Socket hướng kết nối (TCP Socket)

94

Có 1 đường kết nối ảo giữa 2 tiến trình

Một trong 2 tiến trình phải đợi tiến trình kia yêu cầu kết nối.

Có thể sử dụng để liên lạc theo mô hình Client/Server

Trong mô hình Client/Server thì Server lắng nghe và chấp nhận một yêu cầu kết nối

Mỗi thông điệp gửi đều có xác nhận trở về

Các gói tin chuyển đi tuần tự

Page 95: Phan 1   sv

Đặc điểm của Socket không hướng kết nối

95

Hai tiến trình liên lạc với nhau không kết nối trực tiếp

Thông điệp gửi đi phải kèm theo địa chỉ của người nhận

Thông điệp có thể gửi nhiều lần

Người gửi không chắc chắn thông điệp tới tay người nhận Thông điệp gửi sau có thể đến đích trước thông điệp gửi trước đó.

Page 96: Phan 1   sv

IPAddress

96

Trên Internet mỗi 1 trạm đều có 1 định danh duy nhất và được gọi là địa chỉ.

Địa chỉ trên Internet là một tập hợp gồm 4 con số có giá trị từ 0-255 và cách nhau bởi dấu chấm.

Để thể hiện địa chỉ này, người ta có thể viết dưới các dạng sau: Tên: May01, Server, …Địa chỉ IP nhưng đặt trong một chuỗi: "192.168.1.1",

"127.0.0.1“Đặt trong một mảng 4 byte, mỗi byte chứa một số từ 0-

255.Ví dụ: Đổi địa chỉ 192.168.1.2 ra số, ta tính như sau:

2 * 256 ^ 3 + 1 * 256 ^ 2 + 168 * 256 ^ 1 + 192 * 256 ^ 0 = 33663168

Page 97: Phan 1   sv

Lớp IPAddress: các thành viên

97

Page 98: Phan 1   sv

Lớp IPAddress: các thành viên

98

Page 99: Phan 1   sv

Lớp IPAddress: các thành viên

99

Page 100: Phan 1   sv

IPAddress: Ví dụ tạo địa chỉ

100

Cách 1: Dùng hàm khởi tạoByte[] b = new Byte[4]; b[0] = 192; b[1] = 168; b[2] = 10; b[3] = 10;IPAddress Ip1 = new IPAddress(b);

Cách 2: Dùng hàm khởi tạoIPAddress Ip2 = new IPAddress(16885952);

Cách 3: Dùng hàm khởi tạoIPAddress Ip3 = IPAddress.Parse("172.16.1.1")

Cách 4: Thông qua tính toánLong So = 192* 256^0+168* 256^1+1* 256^2 + 2*256^3;IPAddress Ip4 = new IPAddress(So);

Page 101: Phan 1   sv

IPAddress: Ví dụ kiểm tra địa chỉ

101

private void KiemTra()

{

IPAddress ip;

String Ip4 = "127.0.0.1";

String Ip5 = "999.0.0.1";

MessageBox.Show(IPAddress.TryParse(Ip4, out ip).ToString());

MessageBox.Show(IPAddress.TryParse(Ip5, out ip).ToString()); }

Page 102: Phan 1   sv

IPAddress: Ví dụ chuyển địa chỉ hiện hành ra mảng

102

void ChuyenDoi()

{

IPAddress Ip3 = new IPAddress(16885952);

Byte[] b= new Byte[4]; b = Ip3.GetAddressBytes();

MessageBox.Show("Address: " + b[0] + "." + b[1] + "." + b[2] + "." + b[3])

}

Page 103: Phan 1   sv

Lớp IPEndpoint

103

Trong mạng, để hai trạm có thể trao đổi thông tin được với nhau thì chúng cần phải biết được địa chỉ (IP) của nhau và số hiệu cổng mà hai bên dùng để trao đổi thông tin.

Lớp IPAddress mới chỉ cung cấp địa chỉ IP (IPAddress), như vậy vẫn còn thiếu số hiệu cổng (Port number).

Lớp IPEndpoint chính là lớp chứa đựng cả IPAddress và Port number.

Page 104: Phan 1   sv

Lớp IPEndpoint: các thành viên

104

Page 105: Phan 1   sv

Lớp IPEndpoint: các thành viên

105

Page 106: Phan 1   sv

Lớp IPEndpoint: ví dụ khởi tạo

106

private void TaoEndpoint()

{// Tạo một địa chỉ IPIPAddress IPAdd = IPAddress.Parse("127.0.0.1");// Truyền vào cho hàm khởi tạo để tạo IPEndpointIPEndPoint IPep = new IPEndPoint(IPAdd, 10000);

}

private void TaoEndPointBoiTenMay()

{IPAddress IPAdd;//tạo đối tượng IP từ tên của máy thông qua Phương thức tĩnh

Dns.GetHostAddresses của lớp DNSIPAdd = Dns.GetHostAddresses("Localhost")[0];IPEndPoint IPep = new IPEndPoint(IPAdd, 10000);}

Page 107: Phan 1   sv

Lớp IPEndpoint: ví dụ khởi tạo

107

Lưu ý : Vì một máy tính có thể có nhiều card mạng (Interface) do vậy có thể có nhiều hơn 1 địa chỉ IP.

Hàm GetHostAddresses sẽ trả về cho chúng ta một mảng chứa tất cả các địa chỉđó.

Chúng ta lấy chỉ số là 0 để chọn địa chỉ của card mạng đầu tiên.

Page 108: Phan 1   sv

Lớp IPHostEntry

108

IPHostEntry là lớp chứa (Container) về thông tin địa chỉ của các máy trạm trên Internet.

Lưu ý: Nó chỉ là nơi để "chứa", do vậy trước khi sử dụng cần phải “nạp" thông tin vào cho nó.

Lớp này rất hay được dùng với lớp DNS

Page 109: Phan 1   sv

Lớp IPHostEntry: các thành viên

109

Page 110: Phan 1   sv

Lớp DNS

110

DNS (Domain Name Service) là một lớp giúp chúng ta trong việc phân giải tên miền (Domain Resolution) đơn giản.

Phân giải tên miền tức là: Đầu vào là tên của máy trạm thì đầu ra sẽ cho ta địa chỉ IP tương ứng của máy đó, ví dụ: ServerCNTT 192.168.3.8

Ngoài ra lớp Dns còn có rất nhiều phương thức cho chúng ta thêm thông tin về máy cục bộ như tên, địa chỉ, v.v.

Page 111: Phan 1   sv

Lớp DNS: các thành viên

111

Page 112: Phan 1   sv

Lớp DNS: các thành viên

112

Page 113: Phan 1   sv

Lớp DNS: các thành viên

113

Lưu ý: Đây là các phương thức tĩnh, do vậy khi gọi thì gọi trực tiếp từ tên lớp mà không cần phải khai báo một đối tượng mới của lớp này.

Ví dụ: Dns.Resolve, Dns.GetHostname, Dns.GetHostEntry, v.v…

Page 114: Phan 1   sv

Lớp DNS: ví dụ 1

114

private void ShowIPs(){// Lấy tất cả địa chỉIP của máyIPAddress[] add = Dns.GetHostAddresses(“ABC-PC");

foreach (IPAddress ip in add) {MessageBox.Show(ip.ToString());}//for (int i = 0; i < add.Length; i++)//{// MessageBox.Show(add[i].ToString());//}}

Page 115: Phan 1   sv

Lớp DNS: ví dụ 1

115

private void CreatIPHostEntry() {

IPHostEntry iphe1, iphe2, iphe3;

IPAddress ipadd = IPAddress.Parse("127.0.0.1");

iphe1 = Dns.GetHostEntry("Notebook");

iphe2 = Dns.GetHostEntry("127.0.0.1");

iphe3 = Dns.GetHostEntry(ipadd);

MessageBox.Show(iphe1.HostName);

MessageBox.Show(iphe2.HostName) ;

MessageBox.Show(iphe3.HostName) ;

}

Page 116: Phan 1   sv

SOCKETusing System;

using System.Net;

using System.Net.Sockets;

class SockProp

{ public static void Main ()

{ IPAddress ia = IPAddress.Parse("127.0.0.1");

IPEndPoint ie = new IPEndPoint(ia, 8000);

Socket test = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

Console.WriteLine("AddressFamily: {0}", test.AddressFamily);

Console.WriteLine("SocketType: {0}", test.SocketType);

Console.WriteLine("ProtocolType: {0}", test.ProtocolType);

Console.WriteLine("Blocking: {0}", test.Blocking);

test.Blocking = false;

Console.WriteLine("new Blocking: {0}",test.Blocking);

Console.WriteLine("Connected: {0}", test.Connected);

test.Bind(ie);

IPEndPoint iep = (IPEndPoint)test.LocalEndPoint;

Console.WriteLine("Local EndPoint: {0}", iep.ToString());

test.Close();

}

} 116

Page 117: Phan 1   sv

SOCKET

LẬP TRÌNH SOCKET HƯỚNG KẾT NỐI

Lập trình Socket hướng kết nối, giao thức TCP được dùng để thành lập

phiên làm việc giữa hai endpoint.

Khi sử dụng giao thức TCP để thành lập kết nối ta phải đàm phán kết nối

trước nhưng khi kết nối đã được thành lập dữ liệu có thể truyền đi giữa các

thiết bị một cách tin tưởng.

117

Page 118: Phan 1   sv

SOCKETLẬP TRÌNH PHÍA SERVER

Đầu tiên Server sẽ tạo một Socket, Socket này sẽ được gắn vào một địa

chỉ ip và một port cục bộ.

Hàm để thực hiện việc này là hàm Bind().

Hàm Bind() cần một danh đối số là một IPEndPoint cục bộ.

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

server.Bind(ipep);

IPAddress.Any: để chấp nhận kết nối trên bất kỳ card mạng nào

118

Page 119: Phan 1   sv

SOCKET

LẬP TRÌNH PHÍA SERVER

Sau khi Socket đã được gắn kết vào một địa chỉ và một port, Server phải

sẵn sàng chấp nhận kết nối từ Client.

Việc này được thực hiện nhờ vào hàm Listen().

Hàm Listen() có một đối số, đó chính là số Client tối đa mà nó lắng nghe.server.Listen(10);

Tiếp theo Server dùng hàm Accept() để chấp nhận kết nối từ Client:Socket client = server.Accept();

Hàm Accept() sẽ dừng Server lại và chờ cho đến khi nào có Client kết nối

đến và sẽ trả về một Socket khác, Socket này được dùng để trao đổi dữ

liệu với Client.

Khi đã chấp nhận kết nối với Client thì Server có thể gởi và nhận dữ liệu

với Client thông qua phương thức Send() và Receive().string welcome = "Hello Client";

buff = Encoding.ASCII.GetBytes(welcome);

client.Send(buff, buff.Length, SocketFlags.None);119

Page 120: Phan 1   sv

SOCKET

LẬP TRÌNH PHÍA SERVER

Phương thức Send() của Socket dùng để gởi dữ liệu, phương thức này có

một số đối số quan trọng sau:

Buff : mảng các byte cần gởi

Offset: vị trí đầu tiên trong mảng cần gởi

Size: số byte cần gởi

SocketFlags: chỉ ra cách gởi dữ liệu trên Socket

Phương thức Receive() dùng để nhận dữ liệu. Phương thức này có một số

đối số quan trọng sau:

Buff : mảng các byte cần nhận

Offset: vị trí đầu tiên trong mảng cần nhận

Size: số byte cần nhận

SocketFlags: chỉ ra cách nhận dữ liệu trên Socket

120

Page 121: Phan 1   sv

SOCKETusing System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class TcpServerDonGian

{

public static void Main()

{

//Số byte thực sự nhận được dùng hàm Receive()

int byteReceive;

//buffer để nhận và gởi dữ liệu

byte[] buff = new byte[1024];

//EndPoint cục bộ

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);

//Server Socket

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

//Kết nối server với 1 EndPoint

server.Bind(ipep);

//Server lắng nghe tối đa 10 kết nối

server.Listen(10);

Console.WriteLine("Dang cho Client ket noi den...");121

Page 122: Phan 1   sv

SOCKET//Hàm Accept() sẽ block server lại cho đến khi có Client kết nối đến

Socket client = server.Accept();

//Client EndPoint

IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;

Console.WriteLine("Da ket noi voi Client {0} tai port {1}",

clientep.Address, clientep.Port);

string welcome = "Hello Client";

//Chuyển chuỗi thành mảng các byte

buff = Encoding.ASCII.GetBytes(welcome);

//Gởi câu chào cho Client

client.Send(buff, buff.Length, SocketFlags.None);

while (true)

{ //Reset lại buffer

buff = new byte[1024];

//Lấy số byte thực sự nhận được

byteReceive = client.Receive(buff);

//Nếu Client ngắt kết nối thì thoát khỏi vòng lặp

if (byteReceive == 0) break;

Console.WriteLine(Encoding.ASCII.GetString(buff, 0,

byteReceive));

//Sau khi nhận dữ liệu xong, gởi lại cho Client

client.Send(buff, byteReceive, SocketFlags.None);

}122

Page 123: Phan 1   sv

SOCKETConsole.WriteLine("Da dong ket noi voi Client: {0}",

clientep.Address);

//Đóng kết nối

client.Close();

server.Close();

}

}

123

Page 124: Phan 1   sv

SOCKETLẬP TRÌNH PHÍA CLIENT

Client phải gắn kết một địa chỉ của một Socket đã được tạo ra nhưng sử

dụng phương thức Connect().

Phương thức Connect() yêu cầu một IPEndPoint của Server mà Client cần

kết nối đến.

IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

try

{

server.Connect(ipep);

}catch (SocketException e)

{

Console.WriteLine("Không thể kết nối đến Server");

Console.WriteLine(e.ToString());

return;

}

Phương thức Connect() sẽ dừng lại cho đến khi Client kết nối được với Server124

Page 125: Phan 1   sv

SOCKETLẬP TRÌNH PHÍA CLIENT

Khi kết nối được thành lập, Client dùng phương thức Send() và Receive()

của lớp Socket để gởi và nhận dữ liệu.

Khi quá trình trao đổi dữ liệu đã hoàn tất, đối tượng Socket phải được đóng

lại.

Client Socket dùng phương thức Shutdown() để dừng Socket và dùng

phương thức Close() để thực sự đóng phiên làm việc.

Phương thức Shutdown() của Socket dùng một tham số để quyết định cách

Socket sẽ dừng lại. Các phương thức đó là:

Giá trị Mô tả

SocketShutdown.Both Ngăn cản gởi và nhận dữ liệu trên Socket.

SocketShutdown.Receive Ngăn cản nhận dữ liệu trên Socket. Cờ RST sẽ được gởi nếu có

thêm dữ liệu được nhận.

SocketShutdown.Send Ngăn cản gởi dữ liệu trên Socket. Cờ FIN sẽ được gởi sau khi tất

cả dữ liệu còn lại trong buffer đã được gởi đi.

125

Page 126: Phan 1   sv

SOCKET

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class SimpleTcpClient

{

public static void Main()

{

//Buffer để gởi và nhận dữ liệu

byte[] buff = new byte[1024];

//Chuỗi nhập vào và chuỗi nhận được

string input, stringData;

//IPEndPoint ở server

IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"),

5000);

//Server Socket

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Stream, ProtocolType.Tcp);

126

Page 127: Phan 1   sv

SOCKET//Hàm Connect() sẽ bị block lại và chờ khi kết nối được với server

try

{

server.Connect(ipep);

}

//Quá trình kết nối có thể xảy ra lỗi nên phải dùng try, catch

catch (SocketException e)

{

Console.WriteLine("Không thể kết nối đến Server");

Console.WriteLine(e.ToString());

return;

}

//Số byte thực sự nhận được

int byteReceive = server.Receive(buff);

//Chuỗi nhận được

stringData = Encoding.ASCII.GetString(buff, 0, byteReceive);

Console.WriteLine(stringData);

127

Page 128: Phan 1   sv

SOCKETwhile (true)

{ //Nhập dữ liệu từ bàn phím

input = Console.ReadLine();

//Nếu nhập exit thì thoát và đóng Socket

if (input == "exit") break;

//Gởi dữ liệu cho server

server.Send(Encoding.ASCII.GetBytes(input));

//Reset lại buffer

buff = new byte[1024];

//Số byte thực sự nhận được

byteReceive = server.Receive(buff);

//Chuỗi nhận được

stringData = Encoding.ASCII.GetString(buff, 0,

byteReceive);

Console.WriteLine(stringData);

}

Console.WriteLine("Dong ket noi voi server...");

//Dừng kết nối, không cho phép nhận và gởi dữ liệu

server.Shutdown(SocketShutdown.Both);

//Đóng Socket

server.Close();

}

}128

Page 129: Phan 1   sv

UDP SOCKETMô hình lập trình Socket phi kết nối

Phương thức Connect() không cần dùng trong chương trình UDP Client.

Giao thức phi kết nối UDP không đảm bảo dữ liệu được truyền tới đích.

Socket phi kết nối cung cấp hai phương thức SendTo() và

ReceiveFrom() để thực hiện việc kết nối.

Page 130: Phan 1   sv

UDP SOCKET

Lập trình phía Server

UDP là một giao thức phi kết nối do đó chỉ làm hai việc để tạo ra một ứng

dụng Server gởi và nhận dữ liệu:

• Tạo ra Socket

• Kết nối Socket đến một IPEndPoint cục bộ

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);

Socket newsock = new Socket(AddressFamily.InterNetwork,

SocketType.Dgram, ProtocolType.Udp);

newsock.Bind(ipep);

1. Tạo ra

IPEndPoint2. Tạo ra

Socket

3. Kết nối

Socket với

IPEndPoint

Để thực hiện truyền thông phi kết nối, phải chỉ ra SocketType là Datagram

và ProtocolType là Udp.

Page 131: Phan 1   sv

UDP SOCKETLập trình phía Serverusing System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class SimpleUdpSrvr

{ public static void Main()

{ int recv;

byte[] data = new byte[1024];

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);

Socket newsock = new Socket(AddressFamily.InterNetwork,

SocketType.Dgram, ProtocolType.Udp);

newsock.Bind(ipep);

Console.WriteLine("Dang cho Client ket noi den...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

EndPoint Remote = (EndPoint)(sender);

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine("Thong diep duoc nhan tu {0}:",

Remote.ToString());

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

Page 132: Phan 1   sv

UDP SOCKET

Lập trình phía Serverstring welcome = "Hello Client";

data = Encoding.ASCII.GetBytes(welcome);

newsock.SendTo(data, data.Length, SocketFlags.None, Remote);

while (true)

{

data = new byte[1024];

recv = newsock.ReceiveFrom(data, ref Remote);

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

newsock.SendTo(data, recv, SocketFlags.None, Remote);

}

}

}

Sau khi gắn Socket vào một IPEndPoint, Server sẽ chờ Client kết nối đến,

khi Client kết nối đến, Client sẽ gởi thông điệp đến Server. Server sau khi

nhận được thông điệp từ Client nó sẽ gởi câu chào ngược lại cho Client.

Page 133: Phan 1   sv

UDP SOCKET

Lập trình phía Clientusing System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class SimpleUdpClient

{ public static void Main()

{ byte[] data = new byte[1024];

string input, stringData;

IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Dgram, ProtocolType.Udp);

string welcome = "Hello server";

data = Encoding.ASCII.GetBytes(welcome);

server.SendTo(data, data.Length, SocketFlags.None, ipep);

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

EndPoint Remote = (EndPoint)sender;

data = new byte[1024];

int recv = server.ReceiveFrom(data, ref Remote);

Console.WriteLine("Thong diep duoc nhan tu {0}:", Remote.ToString());

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

Page 134: Phan 1   sv

UDP SOCKET

Lập trình phía Clientwhile (true)

{ input = Console.ReadLine();

if (input == "exit") break;

server.SendTo(Encoding.ASCII.GetBytes(input), Remote);

data = new byte[1024];

recv = server.ReceiveFrom(data, ref Remote);

stringData = Encoding.ASCII.GetString(data, 0, recv);

Console.WriteLine(stringData);

}

Console.WriteLine("Dang dong client");

server.Close();

}

}

Client gởi thông điệp đến Server và chờ câu chào trả về từ Server.

Chương trình SimpleUdpClient đọc dữ liệu nhập vào từ bàn phím rồi gởi

đến và chờ dữ liệu từ Server gởi trả về. Khi Server gởi trả dữ liệu về, Client

sẽ lấy thông điệp đó ra và hiển thị lên màn hình.

Chương trình UDP Server sẽ không biết khi nào Client ngắt kết nối do đó

khi Client ngắt kết nối thì phải gởi thông điệp ngắt kết nối cho Server biết.

Page 135: Phan 1   sv

UDP SOCKET

Phân biệt các thông điệp UDP Mỗi phương thức ReceiveFrom() chỉ đọc dữ liệu được gởi từ một phương

thức SendTo().

Khi UDP Socket có thể nhận thông điệp từ bất kỳ Client nào.

Để UDP Socket phân biệt được Client gởi dữ liệu thì mỗi thông điệp phải

được chứa trong một gói tin riêng và được đánh dấu bởi thông tin IP của

thiết bị gởi.

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class TestUdpSrvr

{

Chương trình UDP Server

Page 136: Phan 1   sv

UDP SOCKET

public static void Main()

{ int recv; byte[] data = new byte[1024];

IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 5000);

Socket newsock = new Socket(AddressFamily.InterNetwork,

SocketType.Dgram, ProtocolType.Udp);

newsock.Bind(ipep);

Console.WriteLine("Dang cho client ket noi den...");

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

EndPoint tmpRemote = (EndPoint)(sender);

recv = newsock.ReceiveFrom(data, ref tmpRemote);

Console.WriteLine("Thong diep duoc nhan tu {0}:", tmpRemote.ToString());

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

string welcome = "Xin chao client";

data = Encoding.ASCII.GetBytes(welcome);

newsock.SendTo(data, data.Length, SocketFlags.None,tmpRemote);

for (int i = 0; i < 5; i++)

{ data = new byte[1024];

recv = newsock.ReceiveFrom(data, ref tmpRemote);

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

}

newsock.Close();

}

}

Chương trình UDP Server

Page 137: Phan 1   sv

UDP SOCKET

using System;

using System.Net;

using System.Net.Sockets;

using System.Text;

class TestUdpClient

{ public static void Main()

{ byte[] data = new byte[1024];

IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5000);

Socket server = new Socket(AddressFamily.InterNetwork,

SocketType.Dgram, ProtocolType.Udp);

string welcome = "Xin chao Server";

data = Encoding.ASCII.GetBytes(welcome);

server.SendTo(data, data.Length, SocketFlags.None, ipep);

IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);

EndPoint tmpRemote = (EndPoint)sender;

data = new byte[1024];

int recv = server.ReceiveFrom(data, ref tmpRemote);

Console.WriteLine("Thong diep duoc nhan tu {0}:",

tmpRemote.ToString());

Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));

Chương trình UDP Client

Page 138: Phan 1   sv

UDP SOCKET

server.SendTo(Encoding.ASCII.GetBytes("Thong diep 1"), tmpRemote);

server.SendTo(Encoding.ASCII.GetBytes("Thong diep 2"), tmpRemote);

server.SendTo(Encoding.ASCII.GetBytes("Thong diep 3"), tmpRemote);

server.SendTo(Encoding.ASCII.GetBytes("Thong diep 4"), tmpRemote);

server.SendTo(Encoding.ASCII.GetBytes("Thong diep 5"), tmpRemote);

Console.WriteLine("Dang dong client");

server.Close();

}

}

Chương trình UDP Client

UDP Server nhận biết

được các thông điệp

riêng rẽ

Kết quả ở Server

Page 139: Phan 1   sv

Lớp UDPClient

139

Giao thức UDP (User Datagram Protocol hay User Define Protocol) là một giao thức phi kết nối (Connectionless)

Nói cách khác là không cần thiết lập kết nối giữa hai bên khi tiến hành trao đổi thông tin.

Giao thức này không tin cậy bằng giao thức TCP nhưng tốc độ lại nhanh và dễ cài đặt. Ngoài ra, với giao thức UDP ta còn có thể gửi các gói tin quảng bá (Broadcast) cho đồng thời nhiều máy.

Page 140: Phan 1   sv

Lớp UDPClient – Trình tự kết nối

140

Page 141: Phan 1   sv

Lớp UDPClient: các thành viên

141

Page 142: Phan 1   sv

Lớp UDPClient: các thành viên

142

Page 143: Phan 1   sv

Lớp UDPClient: các thành viên

143

Page 144: Phan 1   sv

Lớp UDPClient

144

Page 145: Phan 1   sv

Lớp UDPClient

145

Page 146: Phan 1   sv

Tổng kết: Lớp UDPClient

146

Khi muốn gửi dữ liệu qua mạng bằng lớp UDPClient, làm đơn giản như sau:

Tạo một UDPClient và gán cho nó một số hiệu cổng. Ví dụ: UDPClient udp = new UDPClient(1000)

Tạo một địa chỉ IP ứng với địa chỉ của máy mà ta muốn giao tiếp bằng IPEndPoint hoặc IPAddress hoặc IPHostEntry. (Lưu ý: Nếu dùng Dns.GetHostEntry thì ta có thể truyền vào là tên của máy. Sau đó muốn lấy địa chỉ thì: Dns.GetHostEntry("Tên_Máy").Address[0])

Page 147: Phan 1   sv

Tổng kết: Lớp UDPClient

147

Gửi dữ liệu đi: Bước 1: Chuyển chuỗi thành mảng byte

Bước 2: Gọi phương thức Send, trong đó truyền địa chỉ IP của máy ở xa mà ta vừa tạo ở 2 và thêm vào số hiệu cổng mà máy ở xa đang dùng để nhận dữ liệu.

Khi nhận: Dùng phương thức Receive để nhận dữ liệu về. Khi đó chúng ta cần tạo một đối tượng IPEndPoint với địa chỉ và số hiệu cổng của máy ở xa mà chúng ta muốn nhận dữ liệu. Phương thức này trả về dữ liệu ở dạng mảng byte, do vậy để chuyển sang dạng chuỗi ký tự thì cần dùng lớp Encoding để chuyển đổi.

Page 148: Phan 1   sv

Lớp TCPClient

148

Để đảm bảo độ tin cậy trong các ứng dụng mạng, người ta còn dùng một giao thức khác, gọi là giao thức có kết nối: TCP (Transport Control Protocol).

Trên Internet chủ yếu là dùng loại giao thức này, ví dụ như Telnet, HTTP, SMTP, POP3… Để lập trình theo giao thức TCP, .NET cung cấp hai lớp có tên là TCPClient và TCPListener.

Page 149: Phan 1   sv

Lớp TCPClient

149

Page 150: Phan 1   sv

Lớp TCPClient

150

Page 151: Phan 1   sv

Lớp TCPClient

151

Page 152: Phan 1   sv

Lớp TCPClient: trình tự kết nối

152

Bước 1: Tạo một đối tượng TCPClient

Bước 2: Kết nối đến máy chủ (Server) dùng phương thức Connect

Bước 3: Tạo 2 đối tượng StreamReader (Receive) và StreamWriter (Send) và “nối” với GetStream của TCPClient

Bước 4: Dùng đối tượng StreamWriter.Writeline/Write vừa tạo ở

trên để gửi dữ liệu đi.

Dùng đối tượng StreamReader.Readline/Read vừa tạo ở trên để đọc dữ liệu về.

Bước 5: Đóng kết nối.

Page 153: Phan 1   sv

Lớp TCPClient: trình tự kết nối

153

Nếu muốn gửi/nhận dữ liệu ở mức byte (nhị phân) thì dựng NetworkStream(truyền GetStream cho NetworkStream)

Page 154: Phan 1   sv

TcpClient

154

Ví dụ sử dụng TcpClient

Page 155: Phan 1   sv

Chương trình chat dùng TCPClient

155

class Connection

{TcpClient tcpClient; private Thread thrSender;private StreamReader srReceiver;private StreamWriter swSender;private string currUser; private string strResponse;public Connection(TcpClient tcpCon) {

tcpClient = tcpCon;thrSender = new Thread(AcceptClient); thrSender.Start();

}

Page 156: Phan 1   sv

Chương trình chat dùng TCPClient

156

private void CloseConnection()

{

tcpClient.Close();

srReceiver.Close();

swSender.Close();

}

private void AcceptClient()

{

srReceiver = new System.IO.StreamReader(tcpClient.GetStream());

swSender = new System.IO.StreamWriter(tcpClient.GetStream());

currUser = srReceiver.ReadLine();

if (currUser != "")

{

if (ChatServer.htUsers.Contains(currUser) == true)

{

swSender.WriteLine("0|This username already exists.");

swSender.Flush();

CloseConnection();

return;

}

Page 157: Phan 1   sv

Chương trình chat dùng TCPClient

157

else if (currUser == "Administrator")

{

swSender.WriteLine("0|This username is reserved.");

swSender.Flush();

CloseConnection();

return;

}

else {

swSender.WriteLine("1");

swSender.Flush();

ChatServer.AddUser(tcpClient, currUser);

}

Page 158: Phan 1   sv

Chương trình chat dùng TCPClient

158

}

else {

CloseConnection();

return;

}

try {

while ((strResponse = srReceiver.ReadLine()) != "")

{

if (strResponse == null) {

ChatServer.RemoveUser(tcpClient);

}

Page 159: Phan 1   sv

Chương trình chat dùng TCPClient

159

else {

ChatServer.SendMessage(currUser,

strResponse);

}

}

}

catch {

ChatServer.RemoveUser(tcpClient);

}

Page 160: Phan 1   sv

Lớp TCPClient: ví dụ

160

Tạo một TCP Client và kết nối đến server (FTP Server), sau đó gửi 1 chuỗi

using System.Net.Sockets;

using System.Net;

using System.IO;

public class Form1 {// Tạo địa chỉ ứng với 127.0.0.1Long DiaChi = 1 * 256 ^ 3 + 127 * 256 ^ 0// Tạo một IPEndPoint từ địa chỉ IP và cổng(TCPClient cần một IPEndPoint)IPEndPoint LocalEP = new IPEndPoint(DiaChi, 1000); '// cho cục bộ (client)// Tạo một đối tượng TCP ứng với địa chỉ và cổng ở trênTcpClient tcp = new TcpClient(LocalEP);// Hai luồng nhập và xuất dùng để đọc/ghi vào kết nối TCPStreamWriter Ghi;StreamReader Doc;

Page 161: Phan 1   sv

Lớp TCPClient: ví dụ

161

private void Form1_Load(…) {

tcp.Connect("localhost", 21);MessageBox.Show(tcp.Connected)Doc = new StreamReader(tcp.GetStream());Ghi = new StreamWriter(tcp.GetStream()); //Gửi thử một

chuỗi cho server (FTP Server)Ghi.Writeline("User nhiemtb");Ghi.Flush();// Đọc dữ liệu do Server gửi vềString S = Doc.ReadLine();MessageBox.Show("Dữ liệu gửi từ server : " + S);

}

Page 162: Phan 1   sv

Lớp TCPClient: ví dụ

162

private void Gui_Du_Lieu(String Data)

{Ghi.WriteLine(Data);

Ghi.Flush();

}

}

Page 163: Phan 1   sv

Nhận xét

163

Ở ví dụ trên ta thấy rằng việc gửi thì có thể thực hiện nhiều lần với việc gọi nhiều lần phương thức Gửi_Dữ_Liệu. Tuy nhiên, đối với việc nhận dữ liệu thì ta chỉ thực hiện một lần. Trong trường hợp nếu ta muốn nhận dữ liệu bất cứ khi nào có dữ liệu về thì cần áp dụng kỹ thuật "Thăm dò" và “Kích hoạt sự kiện" như trong phần UDPClient.

Page 164: Phan 1   sv

Nhận xét

164

Ý tưởng thực hiện như sau:

Bước 1: Tạo một TCPClient

Bước 2: Kết nối

Bước 3: Tạo một luồng mới, luồng này "chuyên theo dõi" xem có dữ liệu mới về hay không (chỉ việc kiểm tra bộ đệm (đối tượng StreamReader.EndOfStream = True/False). Nếu bộđệm không rỗng (có dữ liệu mới) thì giá trị EndOfStream sẽ bằng False. Khi có dữ liệu trong bộđệm ta kích hoạt (Raise) sự kiện Có_Dữ_Liệu lên. Trong sự kiện này ta sẽ viết các lệnh xử lý.

Page 165: Phan 1   sv

TCPListener

165

TCPListerner là một lớp cho phép người lập trìnhcó thể xây dựng các ứng dụng Server (Ví dụ nhưSMTP Server, FTP Server, DNS Server, POP3 Server hay server tự định nghĩa ….).

Phương thức khởi tạo

TcpListener (Port:Int32) Tạo một TcpListener và lắng nghe tại cổng chỉ định.

TcpListener(IPEndPoint) Tạo một TcpListener với giá trị Endpoint truyền vào.

TcpListener

(IPAddress, Int32)Tạo một TcpListener và lắng nghe các kết nối đến

tại địa chỉ IP và cổng chỉ định.

Page 166: Phan 1   sv

TCPListener

166

Tên Mô tả

AcceptSocket Chấp nhận một yêu cầu kết nối đang chờ.

AcceptTcpClientChấp nhận một yêu cầu kết nối đang chờ. (Ứng dụng sẽ

dừng tại lệnh này cho đến khi nào có một kết nối đến)

Pending Cho biết liệu có kết nối nào đang chờ đợi không ? (True =

có).

Start Bắt đầu lắng nghe các yêu cầu kết nối.

Stop Dừng việc nghe.

Các phương thức khác

Page 167: Phan 1   sv

TcpListener

167

Ví dụ sử dụng TcpListener

Page 168: Phan 1   sv

168

TcpListenerVí dụ sử dụng TcpListener

Page 169: Phan 1   sv

So sánh TCP & UDP

169