标题：socket
套接字
现象解释socket非常类似于电话插座。以一个国家级电话网为例。电话的通话双方相当于相互通信的2个进程，区号是它的网络地址；区内一个单位的交换机相当于一台主机，主机分配给每个用户的局内号码相当于socket号。任何用户在通话之前，首先要占有一部电话机，相当于申请一个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重要的Socket API：java .net.Socket继承于java.lang.Object，有八个构造器，其方法并不多，下面介绍使用最频繁的三个方法，其它方法大家可以见JDK-1.3文档。
Accept方法用于产生"阻塞"，直到接受到一个连接，并且返回一个客户端的Socket对象实例。"阻塞"是一个术语，它使程序运行暂时"停留"在这个地方，直到一个会话产生，然后程序继续；通常"阻塞"是由循环产生的。
getInputStream方法获得网络连接输入，同时返回一个InputStream对象实例。
getOutputStream方法连接的另一端将得到输入，同时返回一个OutputStream对象实例。注意：其中getInputStream和getOutputStream方法均可能会产生一个IOException，它必须被捕获，因为它们返回的流对象，通常都会被另一个流对象使用。SOCKET连接过程根据连接启动的方式以及本地套接字要连接的目标，套接字之间的连接过程可以分为三个步骤：服务器监听，客户端请求，连接确认。
服务器监听：是服务器端套接字并不定位具体的客户端套接字，而是处于等待连接的状态，实时监控网络状态。
客户端请求：是指由客户端的套接字提出连接请求，要连接的目标是服务器端的套接字。为此，客户端的套接字必须首先描述它要连接的服务器的套接字，指出服务器端套接字的地址和端口号，然后就向服务器端套接字提出连接请求。
连接确认：是指当服务器端套接字监听到或者说接收到客户端套接字的连接请求，它就响应客户端套接字的请求，建立一个新的线程，把服务器端套接字的描述发给客户端，一旦客户端确认了此描述，连接就建立好了。而服务器端套接字继续处于监听状态，继续接收其他客户端套接字的连接请求。如何开发一个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 <sys/types.h>
#include <sys/socket.h>
函数原型 int socket(int domain, int type, int protocol);
第一个参数指定应用程序使用的通信协议的协议族，对于TCP/IP协议族，该参数置PF_INET;
第二个参数指定要创建的套接字类型，流套接字类型为SOCK_STREAM、数据报套接字类型为SOCK_DGRAM、原始套接字SOCK_RAW(WinSock接口并不适用某种特定的协议去封装它，而是由程序自行处理数据包以及协议首部）；
第三个参数指定应用程序所使用的通信协议。此参数可以指定单个协议系列中的不同传输协议。在Internet通讯域中，此参数一般取值为0，系统会根据套接字的类型决定应使用的传输层协议。
该函数如果调用成功就返回新创建的套接字的描述符，如果失败就返回INVALID_SOCKET。（Linux下失败返回-1）套接字描述符是一个整数类型的值。每个进程的进程空间里都有一个套接字描述符表，该表中存放着套接字描述符和套接字数据结构的对应关系。该表中有一个字段存放新创建的套接字的描述符，另一个字段存放套接字数据结构的地址，因此根据套接字描述符就可以找到其对应的套接字数据结构。每个进程在自己的进程空间里都有一个套接字描述符表但是套接字数据结构都是在操作系统的内核缓冲里。创建流套接字的例子：struct protoent *ppe;
ppe=getprotobyname("tcp");
SOCKET ListenSocket=socket(PF_INET,SOCK_STREAM,ppe->p_proto);
PHP语言应用
PHP有强大的SOCKET操作能力，它的处理方式更接近于C，但是没有C的繁琐。可以看作是对C操作的SOCKET的一个封装。
开启一个socket监听示例程序：
<?php
// 设置一些基本的变量
$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函数初始化。
因其PHP中无法使用多线程而限制了PHP socket的使用范围　　
C#语言应用
所谓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)
{
//
}
}
/// <summary>
/// 与接受回调方法一样，读取回调方法也是一个 AsyncCallback 委托。
/// 该方法将来自客户端套接字的一个或多个字节读入数据缓冲区，然后再次调用 BeginReceive 方法，直到客户端发送的数据完成为止。
/// 从客户端读取整个消息后，在控制台上显示字符串，并关闭处理与客户端的连接的服务器套接字。
/// </summary>
/// <param name=”ar”>IAsyncResult 委托</param>
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)
{
//
}
}
/// <summary>
/// 发送
/// </summary>
/// <param name=”ar”></param>
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();
}
/// <summary>
/// 具体处理业务的方法
/// </summary>
/// <returns></returns>
private static string DoSomething(int i)
{
//具体业务代码，返回需要返回的字符串信息
}
/// <summary>
/// 写日志方法
/// </summary>
/// <param name=”strLog”>；写入内容</param>
public static void WriteLog(string strLog)
{
//写入日志代码
}
}
/// 线程执行体，转发消息
/// </summary>
/// <param name=”obj”>；传递给线程执行体的用户名，用以与用户通信 </param>
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}”，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.1Host: ” + hostName +
“Connection: Close”；
//创建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 AM2，原称“Socket M2”，是供AMD桌上型处理器使用的CPU插座，用以取代Socket 754和939，并已于2006年5月23日推出。它拥有940针，支援双通道DDR2 SDRAM，但针脚的排列方式与Socket 940不相同，又因为S940不支援DDR2 SDRAM，因此两者并不兼容。[1]
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及一些其他厂商的产品。此类接口目前已被淘汰，只有部分老产品才能见到。