IP地址
为了使网络上的计算机能够彼此识别对方,每台计算机都需要一个IP地址以标识自己。IP地址由IP协议规定,以32位的二进制数示。最新的IPv6协议将IP地址升为128位,这使得IP地址更加广泛,能够很好地解决目前IP地址紧缺的情况,但是IPv6协议距离实际应用还有一段距离,目前多数操作系统和应用软件都是以32位的IP地址为基准。32位的IP地址主要分为两部分,即前缀和后缀。前缀表示计算机所属的物理网络,后缀确定该网络上的唯一一台计算机。在互联网中,每一个物理网络都有一个唯一的网络号。根据网络号的不同,可以将IP地址分为5类,即A类、B类、C类、D类和E类。其中,A类、B类和C类属于基本类;D类用于多播发送;E类属于保留。
在上述IP地址中,有几个I P地址是比较特殊的,有其单独的用途。
网络地址:在IP地址中主机地址为0的表示网络地址。例如,128.111.0.0。
广播地址:在网络号后跟所有位全是1的IP地址,表示广播地址。
回送地址:127.0.0.1表示回送地址,用于测试。
域名
地址解析
所谓地址解析是指将计算机的协议地址解析为物理地址,即MAC地址,又称为媒体设备地址。通常,在网络上由地址解析协议ARP来实现地址解析。下面以本地网络上的两台计算机通信为例介绍ARP协议解析地址的过程。
假设主机A和主机B处于同一个物理网络上,主机A的IP为192.168.1.21,主机B的IP为192.168.1.23,当主机A与主机B进行通信时,主机B的IP地址192.168.1.23将按如下步骤被解析为物理地址。
(1)主机A从本地ARP缓存中查找IP为192.168.1.23对应的物理地址。用户可以在命令窗口中输入“arp -a”命令查看ARP缓存
(2)如果主机A在ARP缓存中没有发现192.168.1.23映射的物理地址,将发送ARP请求帧到本地网络上的所有主机,在ARP请求帧 中包含了主机A的物理地址和IP地址。
(3)本地网络上的其他主机接收到ARP请求帧后,将检查是否与自己的IP地址匹配。如果不匹配,则丢弃ARP请求帧。如果主机B 发现与自己的IP地址匹配,则将主机A的物理地址和IP地址添加到自己的ARP缓存中,然后主机B将自己的物理地址和IP地址发 送到主机A,当主机A接收到主机B发来的信息时,将以这些信息更新ARP缓存。
(4)当主机B的物理地址确定后,主机A就可以与主机B通信了。
端口
在网络上,计算机是通过IP地址来彼此标识自己的,但是当涉及两台计算机之间的具体通信时,还会出现一个问题——如果主机A中的应用程序A1想与主机B中的应用程序B1通信,如何知道主机A中是A1应用程序与主机B中的应用程序通信,而不是主机A中的其他应用程序与主机B中的应用程序通信?反之,当主机B接收到数据时,又如何知道数据是发往应用程序B1的呢(因为在主机B中可以同时运行多个应用程序)?
为了解决上述问题,TCP/IP协议提出了端口的概念,用于标识通信的应用程序。当应用程序(严格说应该是进程)与某个端口绑定后,系统会将收到的给该端口的数据送往该应用程序。端口是用一个16位的无符号整数值来表示的,范围为0~65535。低于256的端口被作为系统的保留端口,用于系统进程的通信;不在这一范围的端口号被称为自由端口,可以由进程自由使用。
server端
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace socketserver
{
class Program
{
static void Main(string[] args)
{
Socket client;//用这个socket与请求连接的客户端通信
//int recv;
//byte[] message = new byte[1024];
Socket ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
IPAddress adr = IPAddress.Parse("127.0.0.1");
IPEndPoint ep = new IPEndPoint(adr, 3000);
ServerSocket.Bind(ep); //类似于客户机的connect()方法
ServerSocket.Listen(3); //开始监听
while (true)
{
if ((client = ServerSocket.Accept()) != null)
{
Console.WriteLine("连接上...发送数据....");
//欲发送的字节数组,以0为结束标记
byte[] msg = Encoding.UTF8.GetBytes("This is a test");
byte[] message = { 10, 20, 30, 40, 50, 60, 0 };
//send方法返回发送的字节数
Console.WriteLine("总计将发送" + client.Send(msg) + "个字节的数据");
Console.WriteLine("结束.");
// Console.ReadLine();
client.Close();
break;
}
}
}
}
}
client端
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace socketclient
{
class Program
{
static void Main(string[] args)
{
Socket Server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP); //建立客户端套接字
IPAddress adr = IPAddress.Parse("127.0.0.1");
IPEndPoint ep = new IPEndPoint(adr, 3000);
Server.Connect(ep); //完成绑定
byte[] buffer = new byte[255];
String data = null;
int recv = 0;
recv = Server.Receive(buffer);
if (recv > 0)
{
Console.WriteLine("连接上...");
Console.WriteLine("从服务器接收数据...");
data = Encoding.UTF8.GetString(buffer, 0, recv);//ASCII.GetString(buffer, 0, recv);
Console.WriteLine(data);
while (true)
{
String input;
input = Console.ReadLine();
if (input == "exit")
{
break;
}
Server.Send(Encoding.ASCII.GetBytes(input));
}
Console.WriteLine("连接断开...");
Server.Shutdown(SocketShutdown.Both);
Server.Close();
}
}
}
}
多线程版
server端
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets; //可以使用套接字
using System.Threading; //可以使用多线程
namespace threadtcpclient
{
class Threadtcpserver
{
private Socket server;
public Threadtcpserver()
{
IPAddress local = IPAddress.Parse("127.0.0.1");
IPEndPoint iep = new IPEndPoint(local, 13000);
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 将套接字与本地终结点绑定
server.Bind(iep);
//在本地13000端口号上进行监听
server.Listen(20);
Console.WriteLine("等待客户机进行连接......");
while (true)
{
// 得到包含客户端信息的套接字
Socket client = server.Accept();
//创建消息服务线程对象
ClientThread newclient = new ClientThread(client);
//把ClientThread 类的ClientService方法委托给线程
Thread newthread = new Thread(new ThreadStart(newclient.ClientService));
// 启动消息服务线程
newthread.Start();
}
}
static void Main(string[] args)
{
Threadtcpserver instance = new Threadtcpserver();
}
}
class ClientThread
{
//connections变量表示连接数
public static int connections = 0;
public Socket service;
int i;
public ClientThread(Socket clientsocket)
{
//service对象接管对消息的控制
this.service = clientsocket;
}
public void ClientService()
{
String data = null;
byte[] bytes = new byte[1024];
if (service != null)
{
connections++;
}
Console.WriteLine("新客户连接建立:{0} 个连接数", connections);
while ((i = service.Receive(bytes)) != 0)
{
data = System.Text.Encoding.UTF8.GetString(bytes, 0, i);
Console.WriteLine("收到的数据: {0}", data);
// 处理客户端发来的消息,这里是转化为大写字母
//data = data.ToUpper();
byte[] msg = Encoding.UTF8.GetBytes("message from server"); //System.Text.Encoding.UTF8.GetBytes(data);
// 发送一条应答消息
service.Send(msg);
Console.WriteLine("发送的数据: {0}", "message from server");
}
//关闭套接字
service.Close();
connections--;
Console.WriteLine("客户关闭连接:{0} 个连接数", connections);
}
}
}
client端
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace threadtcpclient
{
class multithreadclient
{
static void Main(string[] args)
{
Socket client;
byte[] buf = new byte[1024];
string input;
IPAddress local = IPAddress.Parse("127.0.0.1");
IPEndPoint iep = new IPEndPoint(local, 13000);
try
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(iep);
}
catch (SocketException)
{
Console.WriteLine("无法连接到服务器!");
return;
}
while (true)
{
//在控制台上输入一条消息
input = Console.ReadLine();
//输入exit,可以断开与服务器的连接
if (input == "exit")
{
break;
}
client.Send(Encoding.UTF8.GetBytes(input));
//得到实际收到的字节总数
int rec = client.Receive(buf);
Console.WriteLine(Encoding.UTF8.GetString(buf, 0, rec));
}
Console.WriteLine("断开与服务器的连接......");
client.Close();
}
}
}