基本介绍
socket非常类似于电话插座。以一个国家级电话网为例。电话的通话双方相当于相互通信的2个进程,区号是它的网路地址;区内一个单位的交换机相当于一台主机,主机分配给每个使用者的局内号码相当于socket号。任何使用者在通话之前,首先要佔有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,相当于发出连线请求(假如对方不在同一区内,还要拨对方区号,相当于给出网路地址)。对方假如在场并空闲(相当于通信的另一主机开机且可以接受连线请求),拿起电话话筒,双方就可以正式通话,相当于连线成功。双方通话的过程,是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket传送资料和从socket接收资料。通话结束后,一方挂起电话机相当于关闭socket,撤消连线。
电话系统
在电话系统中,一般使用者只能感受到在地电话机和对方电话号码的存在,建立通话的过程,话音传输的过程以及整个电话系统的技术细节对他都是透明的,这也与socket机製非常相似。socket利用网间网通信设施实现进程通信,但它对通信设施的细节毫不关心,只要通信设施能提供足够的通信能力,它就满足了。
至此,我们对socket进行了直观的描述。抽象出来,socket实质上提供了进程通信的端点。进程通信之前,双方首先必须各自建立一个端点,否则是没有办法建立联系并相互通信的。正如打电话之前,双方必须各自拥有一台电话机一样。在网间网内部,每一个socket用一个半相关描述:
(协定,在地地址,在地连线埠)
一个完整的socket有一个在地唯一的socket号,由作业系统分配。
最重要的是,socket 是面向客户/伺服器模型而设计的,针对客户和伺服器程式提供不同的socket 系统调用。客户随机申请一个socket (相当于一个想打电话的人可以在任何一台入网电话上拨号呼叫),系统为之分配一个socket号;伺服器拥有全局公认的 socket ,任何客户都可以向它发出连线请求和信息请求(相当于一个被呼叫的电话拥有一个呼叫方知道的电话号码)。
socket利用客户/伺服器模式巧妙地解决了进程之间建立通信连线的问题。伺服器socket 半相关为全局所公认非常重要。读者不妨考虑一下,两个完全随机的使用者进程之间如何建立通信?假如通信双方没有任何一方的socket 固定,就好比打电话的双方彼此不知道对方的电话号码,要通话是不可能的。
内容介绍
所谓socket通常也称作套接字,应用程式通常通过套接字向网路发出请求或者应答网路请求。以J2SDK-1.3为例,Socket和ServerSocket类库位于java .net包中。ServerSocket用于伺服器端,Socket是建立网路连线时使用的。在连线成功时,套用程式两端都会产生一个Socket实例,操作这个实例,完成所需的会话。对于一个网路连线来说,套接字是平等的,并没有差别,不因为在伺服器端或在客户端而产生不同级别。不管是Socket还是ServerSocket它们的工作都是通过SocketImpl类及其子类完成的。
功能简介
重要的Socket API:java .net.Socket继承于java.lang.Object,有八个构造器,其方法并不多,下面介绍使用最频繁的三个方法,其它方法大家可以见JDK-1.3文档。
Accept方法用于产生"阻塞",直到接受到一个连线,并且返回一个客户端的Socket对象实例。"阻塞"是一个术语,它使程式运行暂时"停留"在这个地方,直到一个会话产生,然后程式继续;通常"阻塞"是由迴圈产生的。
getInputStream方法获得网路连线输入,同时返回一个InputStream对象实例。
getOutputStream方法连线的另一端将得到输入,同时返回一个OutputStream对象实例。注意:其中getInputStream和getOutputStream方法均可能会产生一个IOException,它必须被捕获,因为它们返回的流对象,通常都会被另一个流对象使用
连线过程
根据连线啓动的方式以及在地套接字要连线的目标,套接字之间的连线过程可以分为三个步骤:伺服器监听,客户端请求,连线确认。
伺服器监听:是伺服器端套接字并不定位具体的客户端套接字,而是处于等待连线的状态,即时监控网路状态。
客户端请求:是指由客户端的套接字提出连线请求,要连线的目标是伺服器端的套接字。为此,客户端的套接字必须首先描述它要连线的伺服器的套接字,指出伺服器端套接字的地址和连线埠号,然后就向伺服器端套接字提出连线请求。
连线确认:是指当伺服器端套接字监听到或者说接收到客户端套接字的连线请求,它就回响客户端套接字的请求,建立一个新的执行绪,把伺服器端套接字的描述发给客户端,一旦客户端确认了此描述,连线就建立好了。而伺服器端套接字继续处于监听状态,继续接收其他客户端套接字的连线请求。
如何开发一个Server-Client模型的程式
开发原理:
伺服器,使用ServerSocket监听指定的连线埠,连线埠可以随意指定(由于1024以下的连线埠通常属于保留连线埠,在一些作业系统中不可以随意使用,所以建议使用大于1024的连线埠),等待客户连线请求,客户连线后,会话产生;在完成会话后,关闭连线。
客户端,使用Socket对网路上某一个伺服器的某一个连线埠发出连线请求,一旦连线成功,开启会话;会话完成后,关闭Socket。客户端不需要指定开启的连线埠,通常临时的、动态的分配一个1024以上的连线埠。
Socket接口是TCP/IP网路的API,Socket接口定义了许多函式或常式,程式员可以用它们来开发TCP/IP网路上的应用程式。要学Internet上的TCP/IP网路编程,必须理解Socket接口。Socket接口设计者最先是将接口放在Unix作业系统裏面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网路的Socket资料传输是一种特殊的I/O,Socket也是一种档案描述符。Socket也具有一个类似于开启档案的函式调用Socket(),该函式返回一个整型的Socket描述符,随后的连线建立、资料传输等操作都是通过该Socket实现的。
常用的Socket类型
有两种:流式Socket(SOCK_STREAM)和资料报式Socket(SOCK_DGRAM)。流式是一种面向连线的Socket,针对于面向连线的TCP服务套用;资料报式Socket是一种无连线的Socket,对应于无连线的UDP服务套用。Socket为了建立Socket,程式可以调用Socket函式,该函式返回一个类似于档案描述符的句柄。socket函式原型为:int socket(int domain,int type,int protocol);domain指明所使用的协定族,通常为PF_INET,(其与addrinfo 裏的 AF_INET在现在看来是相同的。只是历史上人们曾构想将AF(地址家族address family)与PF(protocol family 协定家族)分开,但实际上这种区分并未真正推广,所以现在AF_INET和PF_INET具有相同的意义。其中AF_INET是基于IPv4而PF_INET基于IPv6)表示网际网路协定族(TCP/IP协定族);type参数指定socket的类型:SOCK_STREAM 或SOCK_DGRAM,Socket接口还定义了原始Socket(SOCK_RAW),允许程式使用低层协定;protocol通常赋值0。Socket()调用返回一个整型socket描述符,你可以在后面的调用使用它。Socket描述符是一个指向内部资料结构的指针,它指向描述符表入口。调用Socket函式时,socket执行体将建立一个Socket,实际上建立一个Socket意味着为一个Socket资料结构分配存储空间。Socket执行体为你管理描述符表。两个网路程式之间的一个网路连线包括五种信息:通信协定、在地协定地址、在地主机连线埠、远端主机地址和远端协定连线埠。Socket资料结构中包含这五种信息。socket在测量软体中的使用也很广泛。
现在越来越多企业採用这种,当然也有人曾经想将地址与协定分开,但实际的意义上并未实行到,现在还在使用原始的类型,它是指向低层协定的一种。
相关信息
socket函式
套用程式调用socket函式来建立一个能够进行网路通信的套接字。
头档案
#include
#include
函式原型 int socket(int domain, int type, int protocol);
第一个参数指定应用程式使用的通信协定的协定族,对于TCP/IP协定族,该参数置AF_INET;
第二个参数指定要建立的套接字类型,流套接字类型为SOCK_STREAM、资料报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协定去封装它,而是由程式自行处理封包以及协定首部);
第三个参数指定应用程式所使用的通信协定。此参数可以指定单个协定系列中的不同传输协定。在Internet通讯域中,此参数一般取值为0,系统会根据套接字的类型决定应使用的传输层协定。
该函式如果调用成功就返回新建立的套接字的描述符,如果失败就返回INVALID_SOCKET。套接字描述符是一个整数类型的值。每个进程的进程空间裏都有一个套接字描述符表,该表中存放着套接字描述符和套接字资料结构的对应关系。该表中有一个栏位存放新建立的套接字的描述符,另一个栏位存放套接字资料结构的地址,因此根据套接字描述符就可以找到其对应的套接字资料结构。每个进程在自己的进程空间裏都有一个套接字描述符表但是套接字资料结构都是在作业系统的核心缓沖裏。
建立流套接字的例子:
struct protoent *ppe;
ppe=getprotobyname(tcp);
SOCKET ListenSocket=socket(PF_INET,SOCK_STREAM,ppe->p_proto);
PHP语言中的SOCKET
PHP有强大的SOCKET操作能力,它的处理方式更接近于C,但是没有C的繁琐。可以看作是对C操作的SOCKET的一个封装。
开啓一个socket监听示例程式:
// 设定一些基本的变数
$host=192.168.1.99;
$port=1234;
// 设定逾时时间
set_time_limit(0);
// 建立一个Socket
$socket=socket_create(AF_INET,SOCK_STREAM,0) or die(Could not create
socket\n);
//绑定Socket到连线埠
$result=socket_bind($socket,$host,$port) or die(Could not bind to
socket\n);
// 开始监听连结
$result=socket_listen($socket,3) or die(Could not set up socket
listener\n);
// accept incoming connections
// 另一个Socket来处理通信
$spawn=socket_accept($socket) or die(Could not accept incoming
connection\n);
// 获得客户端的输入
$input=socket_read($spawn,1024) or die(Could not read input\n);
// 清空输入字元串
$input=trim($input);
//处理客户端输入并返回结果
$output=strrev($input) .\n;
socket_write($spawn,$output,strlen($output)) or die(Could not write
output\n);
// 关闭sockets
socket_close($spawn);
socket_close($socket);
>
Socket
应用程式通常通过Socket向网路发出请求或者应答网路请求
常用的Socket类型
有两种:流式Socket - SOCK_STREAM
资料报式Socket - SOCK_DGRAM
两种模型:
对等模型
C/S模型
1.对等模型:
1.建立socket:socket
int socket(
int domain,//地址族的类型AF_UNIX AF_INET
int type,//支持的资料格式:流SOCK_STREAM/报文SOCK_DGRAM
int protocol);//支持的协定,建议为0
返回值:
成功返回档案描述符号。
失败返回-1;
2.绑定在地址上(档案目录地址)URL(Universe Resource Location)
协定://路径/档案名称
file:///usr/bin/ls
http://192.168.0.72/index.php
struct sockaddr;
struct sockaddr_un;un=unix
struct sockaddr_in;in=internet
int bind(int fd,//socket描述符号
struct sockaddr*addr,//绑定地址
socklen_t size);//地址长度
3.接收资料
read/recv/recvfrom
4.关闭socket
1.建立socket:socket
2.连线到目标:connect(可选)
3.传送资料:write/send/sendto
4.关闭close
2.C/S模型
Server Client
建立socket:socket 建立socket:socket
绑定地址:bind 建立连线:connect
监听:listen
接收:accept
read/write read/write
close close
int listen(int fd,int num);
0:监听成功
-1:失败
int accept(int fd,
struct sockaddr*addr,//返回连线着的地址
socklen_t* len)//接收返回地址的缓沖长度
返回:
-1:接收失败
>=0:对应客户的档案描述符号
注意:socket函式建立Socket时 是否必须先用WSAStartup函式初始化。
C#语言中的SOCKET
所谓Socket通常也称作“套接字”,套用程式通常通过“套接字”向网路发出请求或者应答网路请求。根据连线啓动的方式以及在地套接字要连线的目标,套接字之间的连线过程可以分为三个步骤:伺服器监听,客户端请求,连线确认。
伺服器监听:是伺服器端套接字并不定位具体的客户端套接字,而是处于等待连线的状态,即时监控网路状态。
客户端请求:是指由客户端的套接字提出连线请求,要连线的目标是伺服器端的套接字。为此,客户端的套接字必须首先描述它要连线的伺服器的套接字,指出伺服器端套接字的地址和连线埠号,然后就向伺服器端套接字提出连线请求。
连线确认:是指当伺服器端套接字监听到或者说接收到客户端套接字的连线请求,它就回响客户端套接字的请求,建立一个新的执行绪,把伺服器端套接字的描述发给客户端,一旦客户端确认了此描述,连线就建立好了。而伺服器端套接字继续处于监听状态,继续接收其他客户端套接字的连线请求。
Socket通信以其传输速度快且稳定的优点在程式开发中套用非常的广泛,下面的範例就简要的介绍了Socket在C#中套用。
public class XmlSocket
{
//非同步socket诊听
// Incoming data from client.从客户端传来的资料
public static string data = null;
// Thread signal.执行绪 用一个指示是否将初始状态设定为终止的布尔值初始化 ManualResetEvent 类的新实例。
public static ManualResetEvent allDone = new ManualResetEvent(false);
//static void Main(string[] args)
//{
// StartListening();
//}
public static void StartListening()
{
// Data buffer for incoming data. 传入资料缓沖
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket. 建立在地连线埠
// The DNS name of the computer
// running the listener is “*******”.
IPAddress ipAddress;
String ipString = ConfigurationManager.AppSettings.Get(“SocketIP”);
if (ipString==null || ipString ==String.Empty) { IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
ipAddress = ipHostInfo.AddressList[0];
}
else
{
ipAddress = IPAddress.Parse(ipString);
}
int port;
String portString = ConfigurationManager.AppSettings.Get(“SocketPort”);
if (portString==null || portString==String.Empty)
{
port = 11001;
}
else
{
port = int.Parse(portString);
}
IPEndPoint localEndPoint = new IPEndPoint(ipAddress,port);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.绑定连线埠和资料
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.设定无信号状态的事件
allDone.Reset();
// Start an asynchronous socket to listen for connections.重新 啓动非同步连线
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
// Wait until a connection is made before continuing.等待连线建立后继续
allDone.WaitOne();
}
}
catch (Exception e)
{
//
}
}
public static void AcceptCallback(IAsyncResult ar)
{
try
{
// Signal the main thread to continue.接受回调方法 该方法的此节向主应用程式执行绪发出信号,
//让它继续处理并建立与客户端的连线
allDone.Set();
// Get the socket that handles the client request.获取客户端请求句柄
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReadCallback),state);
}
catch (Exception e)
{
//
}
}
///
/// 与接受回调方法一样,读取回调方法也是一个 AsyncCallback 委托。
/// 该方法将来自客户端套接字的一个或多个位元组读入资料缓沖区,然后再次调用 BeginReceive 方法,直到客户端传送的资料完成为止。
/// 从客户端读取整个讯息后,在控製台上显示字元串,并关闭处理与客户端的连线的伺服器套接字。
///
/// IAsyncResult 委托
public static void ReadCallback(IAsyncResult ar)
{
try
{
String content = String.Empty;
// Retrieve the state object and the handler socket建立自定义的状态对象 from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;//处理的句柄
// Read data from the client socket. 读出
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
//业务代码
String result = DoSomeThing(…);
String len = Encoding.UTF8.GetBytes(result).Length.ToString().PadLeft(8,’0′);
log.writeLine(len);
Send(len + result,handler);
}
}
catch (Exception e)
{
//
}
}
private static void Send(String data,Socket handler)
{
try
{
// Convert the string data to byte data using UTF8 encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData,0,byteData.Length,0,
new AsyncCallback(SendCallback),handler);
}
catch (Exception e)
{
//
}
}
///
/// 传送
///
///
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.向远端传送资料
int bytesSent = handler.EndSend(ar);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer,0,StateObject.BufferSize,0,new AsyncCallback(ReadCallback),state);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
//
}
}
public static void StopListening()
{
allDone.Close();
log.close();
}
///
/// 具体处理业务的方法
///
///
private static string DoSomething(int i)
{
//具体业务代码,返回需要返回的字元串信息
}
///
/// 写日志方法
///
/// ;写入内容
public static void WriteLog(string strLog)
{
//写入日志代码
}
}
/// 执行绪执行体,转发讯息
///
/// ;传递给执行绪执行体的使用者名称,用以与使用者通信
private void ThreadFunc(object obj)
{
//通过转发表得到当前使用者套接字
Socket clientSkt = _transmit_tb[obj] as Socket;
//主迴圈
while (true)
{
try
{ //接受第一个封包。
//由于程式逻辑结构简单,所以在这裏对客户机传送的第一个包内容作逐一判断,
//这裏的实现不够优雅,但不失为此简单模型的一个解决之道。
byte[] packetBuff = new byte[_maxPacket];
clientSkt.Receive(packetBuff);
string _str = Encoding.Unicode.GetString(packetBuff).TrimEnd(‘\0′);
//如果是发给不线上好友的信息
if (_str.StartsWith(“cmd::FriendMessage”))
{
string UserName = _str.Substring(“cmd::FriendMessage”.Length,20).Trim();
string MessageS = _str.Substring(“cmd::FriendMessage”.Length + 20,_str.Length - ”cmd::FriendMessage”.Length - 20);
SaveMessage(obj as string,UserName,MessageS);
continue;
}
//如果是离线请求
if (_str.StartsWith(“cmd::RequestLogout”))
{
_transmit_tb.Remove(obj);
UpdateFriendList((string)obj,false,”);
// string svrlog = string.Format(“[系统讯息]使用者 {0} 在 {1} 已断开… 当前线上人数: {2}\r\n\r\n”,obj,DateTime.Now,_transmit_tb.Count);
// Console.WriteLine(svrlog);
//向所有客户机传送系统讯息
//foreach (DictionaryEntry de in _transmit_tb)
//{
// string _clientName = de.Key as string;
// Socket _clientSkt = de.Value as Socket;
// _clientSkt.Send(Encoding.Unicode.GetBytes(svrlog));
//}
Thread.CurrentThread.Abort();
}
//如果是请求好友列表
if (_str.StartsWith(“cmd::RequestFriendList”))
{
SerializeFriendList(obj,clientSkt);
// 将该使用者不线上时的信息传送给使用者
DataTable TabMessage = ReadMessage(obj as string);
if (TabMessage != null)
{
foreach (DataRow myrow in TabMessage.Rows)
{
if (myrow[SendUserName].ToString() == ”System::Message”)
{
clientSkt.Send(Encoding.Unicode.GetBytes(myrow[Message].ToString()));
}
else
{
clientSkt.Send(Encoding.Unicode.GetBytes(“cmd::FriendMessage” +myrow[SendUserName].ToString().PadRight(20,’ ’) + myrow[Message].ToString()));
}
}
} //这裏不需要再继续接受后继封包了,跳出当前迴圈体。
continue;
}
////如果是请求好友列表
//if (_str.StartsWith(“cmd::RequestOnLineList”))
//{
// byte[] onlineBuff = SerializeOnlineList();
// //先传送回响信号,使用者客户机的判断
// clientSkt.Send(Encoding.Unicode.GetBytes(“cmd::RequestOnLineList”));
// clientSkt.Send(onlineBuff);
// //这裏不需要再继续接受后继封包了,跳出当前迴圈体。
// continue;
//} //查找使用者
if (_str.StartsWith(“Find::FindFriend”))
{
DataTable TabFind = TabUser.Clone();
DataRow [] FindRow =null ;
string UserName = _str.Substring(“Find::FindFriend”.Length,_str.Length - ”Find::FindFriend”.Length);
if (UserName.Equals(“Find::WhoOnLine”))
{ //看谁线上
FindRow = TabUser.Select(“ ZX = 1″);
}
else//精确查找
{
FindRow = TabUser.Select(“UserName = ‘” + UserName + ”‘”);
}
foreach (DataRow myrow in FindRow)
{
TabFind.ImportRow(myrow);
}
clientSkt.Send(Encoding.Unicode.GetBytes(“Find::FindFriend”));
IFormatter format = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
format.Serialize(stream,TabFind);
stream.Position = 0;
byte[] ret = new byte[_maxPacket];
int count = 0;
count = stream.Read(ret,0,_maxPacket);
while (count >0)
{
clientSkt.Send(ret);
count = stream.Read(ret,0,_maxPacket);
}
clientSkt.Send(Encoding.Unicode.GetBytes(“Find::FindFriendEnd”));
stream.Close();
TabFind = null;
FindRow = null; //这裏不需要再继续接受后继封包了,跳出当前迴圈体。
continue;
} //请求增加好友
if (_str.StartsWith(“Find::AddFriendAsk”))
{
string UserName = _str.Substring(“Find::AddFriendAsk”.Length,_str.Length - ”Find::AddFriendAsk”.Length);
//通过转发表查找接收方的套接字
if (_transmit_tb.Count != 0 && _transmit_tb.ContainsKey(UserName))
{
Socket receiverSkt = _transmit_tb[UserName] as Socket;
receiverSkt.Send(Encoding.Unicode.GetBytes(“Find::AddFriendAsk” + obj as string));
}
//这裏不需要再继续接受后继封包了,跳出当前迴圈体。
continue;
}
//回复答应增加好友
if (_str.StartsWith(“Find::AddFriendYes”))
{
string UserName = _str.Substring(“Find::AddFriendYes”.Length,_str.Length - ”Find::AddFriendYes”.Length);
//// 储存资料
DataTable TabmyFriend = new DataTable() ;
//储存该使用者
TabmyFriend.ReadXml(MyPath + ”\\UserFriend\\” + obj as string + ”.xml”);
DataRow newRow = TabmyFriend.NewRow();
newRow[UserName] = UserName;
TabmyFriend.Rows.Add(newRow);
TabmyFriend.WriteXml(MyPath + ”\\UserFriend\\” + obj as string + ”.xml”,XmlWriteMode.WriteSchema,false);
//储存其好友
TabmyFriend = new DataTable();
TabmyFriend.ReadXml(MyPath + ”\\UserFriend\\” + UserName + ”.xml”);
DataRow newRow1 = TabmyFriend.NewRow();
newRow1[UserName] = obj as string;
TabmyFriend.Rows.Add(newRow1);
TabmyFriend.WriteXml(MyPath + ”\\UserFriend\\” + UserName + ”.xml”,XmlWriteMode.WriteSchema,false);
TabmyFriend = null;
SerializeFriendList(obj,clientSkt);
//”开始”按钮事件
private void button1_Click(object sender,System.EventArgs e) {
//取得预储存的档案名称
string fileName=textBox3.Text.Trim();
//远程主机
string hostName=textBox1.Text.Trim();
//连线埠
int port=Int32.Parse(textBox2.Text.Trim());
//得到主机信息
IPHostEntry ipInfo=Dns.GetHostByName(hostName);
//取得IPAddress[]
IPAddress[] ipAddr=ipInfo.AddressList;
//得到ip
IPAddress ip=ipAddr[0];
//组合出远程终结点
IPEndPoint hostEP=new IPEndPoint(ip,port);
//建立Socket 实例
Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
try
{
//尝试连线
socket.Connect(hostEP);
}
catch(Exception se)
{
MessageBox.Show(“连线错误”+se.Message,”提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//传送给远程主机的请求内容串
string sendStr=”GET / HTTP/1.1\r\nHost: ” + hostName +
“\r\nConnection: Close\r\n\r\n”;
//建立bytes位元组数组以转换传送串
byte[] bytesSendStr=new byte[1024];
//将传送内容字元串转换成位元组byte数组
bytesSendStr=Encoding.ASCII.GetBytes(sendStr);
try
{
//向主机传送请求
socket.Send(bytesSendStr,bytesSendStr.Length,0);
}
catch(Exception ce)
{
MessageBox.Show(“传送错误:”+ce.Message,”提示信息
,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//声明接收返回内容的字元串
string recvStr=”;
//声明位元组数组,一次接收资料的长度为1024位元组
byte[] recvBytes=new byte[1024];
//返回实际接收内容的位元组数
int bytes=0;
//迴圈读取,直到接收完所有资料
while(true)
{
bytes=socket.Receive(recvBytes,recvBytes.Length,0);
//读取完成后退出迴圈
if(bytes〈=0)
break;
//将读取的位元组数转换为字元串
recvStr+=Encoding.ASCII.GetString(recvBytes,0,bytes);
}
//将所读取的字元串转换为位元组数组
byte[] content=Encoding.ASCII.GetBytes(recvStr);
try
{
//建立档案流对象实例
FileStream fs=new FileStream(fileName,FileMode.OpenOrCreate,FileAccess.ReadWrite);
//写入档案
fs.Write(content,0,content.Length);
}
catch(Exception fe)
{
MessageBox.Show(“档案建立/写入错误:”+fe.Message,”提示信息”,MessageBoxButtons.RetryCancel,MessageBoxIcon.Information);
}
//禁用Socket
socket.Shutdown(SocketShutdown.Both);
//关闭Socket
socket.Close();
}
}
CPU插槽类型
Socket 939插槽,是Athlon64处理器所採用的接口类型,针脚数为939针。支持 Socket 939 处理器的主机板只需要4层 PCB。使用普通DDR记忆体。
Socket 940插槽,是Athlon64处理器所採用的接口类型,针脚数为940针。Socket 940接口的处理器支持双通道ECC记忆体,支持 Socket 940 处理器的主机板必须採用6至9层PCB,必须採用带ECC校验的DDR记忆体。
Socket 754插槽,是Athlon64处理器所採用的接口类型,针脚数为754针。Socket 754 接口处理器支持单通道记忆体
LGA 775插槽,是Intel 925X Express和Intel 915 Express晶片组,所採用的接口类型,支持Pentium 4和Pentium 4 Extreme Edition处理器,针脚数为775针。
Socket 478插槽是旧型号Pentium 4系列处理器所採用的接口类型,针脚数为478针。Socket 478的Pentium 4处理器面积很小,其针脚排列极为紧密。採用Socket 478插槽的主机板产品数量众多,是20世纪套用最为广泛的插槽类型。
Socket A接口,也叫Socket 462,是目前AMD公司Athlon XP和Duron处理器的插座标準。Socket A接口具有462插空,可以支持133MHz外频。如同Socket 370一样,降低了製造成本,简化了结构设计。
Socket 423插槽是最初Pentium 4处理器的标準接口,Socket 423的外形和前几种Socket类的插槽类似,对应的CPU针脚数为423。Socket 423插槽多是基于Intel 850晶片组主机板,支持1.3GHz~1.8GHz的Pentium 4处理器。不过随着DDR记忆体的流行,英特尔又开发了支持SDRAM及DDR记忆体的i845晶片组,CPU插槽也改成了Socket 478,Socket 423插槽也就销声匿迹了。
Socket 370架构是英特尔开发出来代替SLOT架构,面板上与Socket 7非常像,也採用零插拔力插槽,对应的CPU是370针脚。
Socket 370主机板多为採用Intel ZX、BX、i810晶片组的产品,其他厂商有VIA Apollo Pro系列、SIS 530系列等。最初认为,Socket 370的CPU升级能力可能不会太好,所以Socket 370的销量总是不如SLOT 1接口的主机板。但在英特尔推出的“铜矿”和”图拉丁”系列CPU, Socket 370接口的主机板一改低端形象,逐渐取代了SLOT 1接口。目前市场中还有极少部分的主机板採用此种插槽。
SLOT 1是英特尔公司为取代Socket 7而开发的CPU接口,并申请的专利。这样其它厂商就无法生产SLOT 1接口的产品,也就使得AMD、VIA、SIS等公司不得不联合起来,对Socket 7接口升级,也得到了Super 7接口。后来随着Super 7接口的兴起,英特尔又将SLOT 1结构主机板的製造授权提供给了VIA、SIS、ALI等主机板厂商,所以这些厂商也相应推出了採用SLOT 1接口的系列主机板,丰富了主机板市场。
SLOT 1是英特尔公司为Pentium Ⅱ系列CPU设计的插槽,其将Pentium Ⅱ CPU及其相关控製电路、二级快取都做在一块子卡上,多数Slot 1主机板使用100MHz外频。SLOT 1的技术结构比较先进,能提供更大的内部传输频宽和CPU性能。採用SLOT 1接口的主机板晶片组有Intel的BX、i810、i820系列及VIA的Apollo系列,ALI 的Aladdin Pro Ⅱ系列及SIS的620、630系列等。此种接口已经被淘汰,市面上已无此类接口的主机板产品。
SLOT 2用途比较专业,都採用于高端伺服器及图形工作站的系统。所用的CPU也是很昂贵的Xeon(至强)系列。Slot 2与Slot 1相比,有许多不同。首先,Slot 2插槽更长,CPU本身也都要大一些。其次,Slot 2能够胜任更高要求的多用途计算处理,这是进入高端企业计算市场的关键所在。在当时标準伺服器设计中,一般厂商只能同时在系统中採用两个 Pentium Ⅱ处理器,而有了Slot 2设计后,可以在一台伺服器中同时採用 8个处理器。而且採用Slot 2接口的Pentium Ⅱ CPU都採用了当时最先进的0.25微米製造工艺。支持SLOT 2接口的主机板晶片组有440GX和450NX。
SLOT A接口类似于英特尔公司的SLOT 1接口,供AMD公司的K7 Athlon使用的。在技术和性能上,SLOT A主机板可完全兼容原有的各种外设扩展卡设备。它使用的并不是Intel的P6 GTL+ 汇流排协定,而是Digital公司的Alpha汇流排协定EV6。EV6架构是种较先进的架构,它採用多执行绪处理的点到点拓扑结构,支持200MHz的汇流排频率。支持SLOT A接口结构的主机板晶片组主要有两种,一种是AMD的AMD 750晶片组,另一种是VIA的Apollo KX133晶片组。此类接口已被Socket A接口全面取代。
Socket 7:Socket在英文裏就是插槽的意思,Socket 7也被叫做Super 7。最初是英特尔公司为Pentium MMX系列CPU设计的插槽,后来英特尔放弃Socket 7接口转向SLOT 1接口,AMD、VIA、ALI、SIS等厂商仍然沿用此接口,直至发展出Socket A接口。该插槽基本特征为321插孔,系统使用66MHz的汇流排。Super 7主机板增加了对100MHz外频和AGP接口类型的支持。
Super 7採用的晶片组有VIA公司的MVP3、MVP4系列,SIS公司的530/540系列及ALI的Aladdin V系列等主机板产品。对应Super 7接口CPU的产品有AMD K6-2、K6-Ⅲ 、Cyrix M2及一些其他厂商的产品。此类接口目前已被淘汰,只有部分老产品才能见到。















