??xml version="1.0" encoding="utf-8" standalone="yes"?>久久福利片,久久精品国产亚洲77777,日韩精品久久久久久http://www.shnenglu.com/aurain/category/6202.html专注Windows下的驱动开发、网l开?/description>zh-cnThu, 13 Mar 2014 18:03:39 GMTThu, 13 Mar 2014 18:03:39 GMT60TCPq接关闭状态{换图http://www.shnenglu.com/aurain/archive/2014/03/13/206149.html?/dc:creator>?/author>Thu, 13 Mar 2014 05:22:00 GMThttp://www.shnenglu.com/aurain/archive/2014/03/13/206149.htmlhttp://www.shnenglu.com/aurain/comments/206149.htmlhttp://www.shnenglu.com/aurain/archive/2014/03/13/206149.html#Feedback0http://www.shnenglu.com/aurain/comments/commentRss/206149.htmlhttp://www.shnenglu.com/aurain/services/trackbacks/206149.html阅读全文

]]>
讨论:关于客户端用何U网l模?/title><link>http://www.shnenglu.com/aurain/archive/2008/10/10/63666.html</link><dc:creator>?/dc:creator><author>?/author><pubDate>Fri, 10 Oct 2008 08:34:00 GMT</pubDate><guid>http://www.shnenglu.com/aurain/archive/2008/10/10/63666.html</guid><wfw:comment>http://www.shnenglu.com/aurain/comments/63666.html</wfw:comment><comments>http://www.shnenglu.com/aurain/archive/2008/10/10/63666.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.shnenglu.com/aurain/comments/commentRss/63666.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aurain/services/trackbacks/63666.html</trackback:ping><description><![CDATA[     摘要: Windows|络应用中,对于服务端我们一般会选择Windows提供的IO模型Q如完成端口模型IOCP?<br>对于客户端需要主动连接多个不同IP的TCP的情况(10或更多)Q那么用什么模型比较好呢?  <a href='http://www.shnenglu.com/aurain/archive/2008/10/10/63666.html'>阅读全文</a><img src ="http://www.shnenglu.com/aurain/aggbug/63666.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aurain/" target="_blank">?/a> 2008-10-10 16:34 <a href="http://www.shnenglu.com/aurain/archive/2008/10/10/63666.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Winsock的两UI/O模式http://www.shnenglu.com/aurain/archive/2008/02/26/43262.html?/dc:creator>?/author>Tue, 26 Feb 2008 07:39:00 GMThttp://www.shnenglu.com/aurain/archive/2008/02/26/43262.htmlhttp://www.shnenglu.com/aurain/comments/43262.htmlhttp://www.shnenglu.com/aurain/archive/2008/02/26/43262.html#Feedback2http://www.shnenglu.com/aurain/comments/commentRss/43262.htmlhttp://www.shnenglu.com/aurain/services/trackbacks/43262.htmld模式Q执?/span>I/O操作完成前会一直进行等待,不会控制权交给E序。套接字 默认为阻塞模式。可以通过多线E技术进行处理?/span>
非阻塞模式:执行I/O操作ӞWinsock函数会返回ƈ交出控制权。这U模式?/span> h比较复杂Q因为函数在没有q行完成p行返回,会不断地q回 WSAEWOULDBLOCK错误。但功能强大?/span>

]]>
|络~程基础http://www.shnenglu.com/aurain/archive/2008/02/25/43202.html?/dc:creator>?/author>Mon, 25 Feb 2008 05:40:00 GMThttp://www.shnenglu.com/aurain/archive/2008/02/25/43202.htmlhttp://www.shnenglu.com/aurain/comments/43202.htmlhttp://www.shnenglu.com/aurain/archive/2008/02/25/43202.html#Feedback0http://www.shnenglu.com/aurain/comments/commentRss/43202.htmlhttp://www.shnenglu.com/aurain/services/trackbacks/43202.htmlBerkeley Socket

          具体的实C是按这个流E图来做的,q里重点是服务端的实现?/p>

int APIENTRY _tWinMain(HINSTANCE hInstance,
                      HINSTANCE hPrevInstance,
                      LPTSTR     lpCmdLine,
                     
int        nCmdShow)
{
            ofstream logfile(
"LogFile.txt");
           
//Initialize winsock
            WSADATA wsaData;
            
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData);
            
if(iResult != NO_ERROR)
             {
                     logfile
<<"Error at WSAStartup() ";    
                     logfile.close();
                    
return 1;
             }
            
else    
                    logfile
<<"Initialize WSAStartup OK!";
    
             
// Create a socket.
             SOCKET serverSocket;
             serverSocket
= socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

             
if(serverSocket == INVALID_SOCKET)
              {    
                      logfile
<<"Error at socket():"<<WSAGetLastError()<<endl;;
                      logfile.close();
                      WSACleanup();
                      
return 1;
              }
             
else
             {
                      logfile
<<"Create socket OK!";
              }

            
// Bind the socket.
              sockaddr_in service;

              service.sin_family
=AF_INET;
              service.sin_addr.s_addr
=inet_addr(HostIp.c_str());
              service.sin_port
=htons(PORT);

              
if (bind(serverSocket,(SOCKADDR*)&service,sizeof(service))==SOCKET_ERROR)
              {
                       logfile
<<"bind() failed"<<GetLastError()<<endl;
                       closesocket(serverSocket);
                       logfile.close();
                      
return 1;
              }
             
else
              {
             logfile
<<"Binding OK!"<<endl;
               }
    
    
              
// Listen on the socket.
               if(listen(serverSocket,1)==SOCKET_ERROR)
               {
                       logfile
<<"Error listening on socket"<<GetLastError()<<endl;
                       logfile.close();
                }
               
else
                {
                       logfile
<<"Listening..."<<endl;
                 }

                
// Accept connections.
                 SOCKET clientSocket;
                 sockaddr_in clientAddr;
                
int clientAddrLen=sizeof(clientAddr);
   
                
while(true)
                 {
                            clientSocket
= SOCKET_ERROR;
                           
while(clientSocket==SOCKET_ERROR)
                            {
                                   clientSocket
=accept(serverSocket,(struct sockaddr*)&clientAddr,&clientAddrLen);      
                             }
                            ReceiveData(clientSocket);    
                   }   

                   closesocket(serverSocket);
                   closesocket(clientSocket);

                  
return 0;
}

//Receive the data
void ReceiveData(SOCKET& clientSocket)
{    
            
int bytesSent;
            
int bytesRecv=SOCKET_ERROR;
            
string sendbuf="";
            
char recvbuf[32]="";
    
            
while(bytesRecv ==SOCKET_ERROR)
             {
                       bytesRecv
=recv(clientSocket,recvbuf,32,0);
    
                        sendbuf
="Received: "+(string)recvbuf;
                        bytesSent
=send(clientSocket,sendbuf.c_str(),(unsigned int)(sendbuf.size()),0);

                        bytesRecv
=SOCKET_ERROR;
                        memset(recvbuf,
'\0',32);
             }
            return;
}

          在接收客L发来数据的地方要做成d@环,如果需要断开q接Q则由客h发送特定的消息然后q行处理。还有需要注意的是上面的HostIp是本机的IP地址QPORT是套接字需要绑定的端口?/p>

]]>
在vc中通过q接池操作mysql(api方式)Q附c++讉Kmysql的封装类http://www.shnenglu.com/aurain/archive/2008/02/21/43049.html?/dc:creator>?/author>Thu, 21 Feb 2008 07:10:00 GMThttp://www.shnenglu.com/aurain/archive/2008/02/21/43049.htmlhttp://www.shnenglu.com/aurain/comments/43049.htmlhttp://www.shnenglu.com/aurain/archive/2008/02/21/43049.html#Feedback1http://www.shnenglu.com/aurain/comments/commentRss/43049.htmlhttp://www.shnenglu.com/aurain/services/trackbacks/43049.html在有大量节点讉K的数据库设计?l常要用到q接池来理所有的q接.
一般方法是:建立两个q接句柄队列,I闲的等待用的队列和正在用的队列.
当要查询时先从空闲队列中获取一个句?插入到正在用的队列,再用q个句柄做数据库操作,完毕后一定要从用队列中删除,再插入到I闲队列.
代码如下Q?br>MySQLMan.h
 // MySQLMan.h: interface for the CMySQLMan class.
//
//////////////////////////////////////////////////////////////////////
#include <mysql.h>
#pragma comment(lib,"libmySQL.lib")

#include <list>

typedef std::list<MYSQL *> CONNECTION_HANDLE_LIST;
typedef std::list<MYSQL *>::iterator ITER_CONNECTION_HANDLE_LIST;

#define CONNECTION_NUM 10 //同时打开的连接数

class CMySQLMan 
{
public:
 CMySQLMan();
 CMySQLMan(const char *host, const char *user, const char *password, const char *db, unsigned int port=3306);
 virtual ~CMySQLMan();
 
public:
 bool ConnectDB();      //q接数据?br> MYSQL_RES* SelectRecord(const char *szSql); //选择记录Q返回结果集
 bool SelectDB(const char *szDB);  //选择数据?br> bool UpdateRecord(const char *szSql); //更新记录
 bool InsertRecord(const char *szSql); //插入记录
 bool DelRecord(const char *szSql);  //删除记录

 BOOL IsEnd(MYSQL_RES *myquery);       //是否最?br> void SeekData(MYSQL_RES *myquery, int offset);    //查找指定数据
 void FreeRecord(MYSQL_RES *myquery);      //释放l果?br> unsigned int GetFieldNum(MYSQL_RES *myquery);    //得到字段?br> MYSQL_ROW GetRecord(MYSQL_RES *myquery);     //得到l果Q一个记录)
 my_ulonglong GetRowNum(MYSQL_RES *myquery);    //得到记录?br> char* OutErrors(MYSQL* pMySql);      //输出错误信息

 char* GetState();      //服务器状?br> char* GetServerInfo();     //服务器信?br> int GetProtocolInfo();     //协议信息
 char* GetHostInfo();     //L信息
 char* GetClientInfo();     //客户Z?br> char* GetFieldName(MYSQL_RES *myquery, int FieldNum);  //字段?/p>

 bool LockTable(const char *TableName, const char *Priority); //对特定表加锁
 bool UnlockTable();      //解锁
 bool SetCharset();
 //int CreateDB(char *db);    //创徏数据库,q回错误信息
 //int DropDB(char *db);     //删除数据?q回错误信息

 MYSQL* GetIdleMySql();     //提取一个空闲句柄供使用
 void SetIdleMysql(MYSQL* pMySql);  //从用队列中释放一个用完毕的句柄Q插入到I闲队列

public:
 //MYSQL  m_mysql;      //数据库连接句?br> MYSQL_ROW m_row;       //记录?单行)
 MYSQL_FIELD *m_field;      //字段信息Q结构体Q?/p>

 //创徏两个队列
 CONNECTION_HANDLE_LIST m_lsBusyList;                //正在使用的连接句?br> CONNECTION_HANDLE_LIST m_lsIdleList;                //未用的q接句柄

 CRITICAL_SECTION m_csList;

public:
 char m_host[20];   //L
 char m_user[20];   //用户?br> char m_password[20];  //密码
 char m_db[20];    //数据库名
 unsigned int m_port;  //端口
};

MySQLMan.cpp
// MySQLMan.cpp: implementation of the MySQLMan class.
//
//////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#include "MySQLMan.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMySQLMan::CMySQLMan()
{
 
}

CMySQLMan::CMySQLMan(const char *host, const char *user, const char *password, const char *db, unsigned int port/* =3306 */)
{
 strcpy(m_host, host);
 strcpy(m_user, user);
 strcpy(m_password, password);
 strcpy(m_db, db);
 m_port = port;

 InitializeCriticalSection(&m_csList);
}

CMySQLMan::~CMySQLMan()
{
 for (ITER_CONNECTION_HANDLE_LIST iter=m_lsBusyList.begin(); iter != m_lsBusyList.end(); iter++)
 {
  mysql_close((*iter));
 }

 for (ITER_CONNECTION_HANDLE_LIST iter=m_lsIdleList.begin(); iter != m_lsIdleList.end(); iter++)
 {
  mysql_close((*iter));
 }

 DeleteCriticalSection(&m_csList);
}

bool CMySQLMan::ConnectDB()
{
 //同时打开CONNECTION_NUM个连?br> try
 {
  for (int i=0; i<CONNECTION_NUM; ++i)
  {
   MYSQL *pMySql = mysql_init((MYSQL*)NULL);
   if (pMySql != NULL)
   {
    if (!mysql_real_connect(pMySql,m_host,m_user,m_password,m_db,m_port,NULL,0))
    {
     OutErrors(pMySql);
     return false;
    }
    m_lsIdleList.push_back(pMySql);
   }
  }
 }
 catch (...)
 {
  return false;
 }
 return true;
}

MYSQL* CMySQLMan::GetIdleMySql()
{
 MYSQL* pMySql = NULL;
 EnterCriticalSection(&m_csList);
 if (m_lsIdleList.size() > 0)
 {
  pMySql = m_lsIdleList.front();
  m_lsIdleList.pop_front();
  m_lsBusyList.push_back(pMySql);
 }
 else
 {
  pMySql = NULL;
 }
 LeaveCriticalSection(&m_csList);

 return pMySql;
}

void CMySQLMan::SetIdleMysql(MYSQL* pMySql)
{
 EnterCriticalSection(&m_csList);
 m_lsBusyList.remove(pMySql);
 m_lsIdleList.push_back(pMySql);
 LeaveCriticalSection(&m_csList);
}

MYSQL_RES* CMySQLMan::SelectRecord(const char *szSql)
{
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return NULL;
 }
 if(mysql_query(pMySql,szSql))
  return NULL;
 MYSQL_RES *myquery = NULL;
 myquery = mysql_store_result(pMySql);
 SetIdleMysql(pMySql);

 return myquery;
}

bool CMySQLMan::InsertRecord(const char *szSql)
{
 bool bRet = false;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if(mysql_query(pMySql,szSql))
 {
  bRet = true;
 }
 SetIdleMysql(pMySql);

 return bRet;
}

bool CMySQLMan::UpdateRecord(const char *szSql)
{
 bool bRet = false;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if(mysql_query(pMySql,szSql))
 {
  bRet = true;
 }
 SetIdleMysql(pMySql);

 return bRet;
}

bool CMySQLMan::DelRecord(const char *szSql)
{
 bool bRet = false;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if(mysql_query(pMySql,szSql))
 {
  bRet = true;
 }
 SetIdleMysql(pMySql);

 return bRet;
}

bool CMySQLMan::SelectDB(const char *szDB)
{
 bool bRet = false;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if (mysql_select_db(pMySql,szDB))
  bRet = false; 
 else
  bRet = true;
 SetIdleMysql(pMySql);

 return bRet;
}

my_ulonglong CMySQLMan::GetRowNum(MYSQL_RES *myquery)
{
 return mysql_num_rows(myquery);
}

MYSQL_ROW CMySQLMan::GetRecord(MYSQL_RES *myquery)
{
 m_row = mysql_fetch_row(myquery);

 return m_row;
}

unsigned int CMySQLMan::GetFieldNum(MYSQL_RES *myquery)
{
 return mysql_num_fields(myquery);
}

void CMySQLMan::FreeRecord(MYSQL_RES *myquery)
{
 mysql_free_result(myquery);
}

//int CMySQLMan::CreateDB(char *db)
//{
// return mysql_create_db(&m_mysql,db);
//}

void CMySQLMan::SeekData(MYSQL_RES *myquery, int offset)
{
 mysql_data_seek(myquery,offset);
}


char * CMySQLMan::OutErrors(MYSQL *pMySql)
{
 return const_cast<char *>(mysql_error(pMySql));
}

BOOL CMySQLMan::IsEnd(MYSQL_RES *myquery)
{
 return mysql_eof(myquery);
}

char* CMySQLMan::GetFieldName(MYSQL_RES *myquery, int FieldNum)
{
 m_field = mysql_fetch_field_direct(myquery, FieldNum);

 return m_field->name;
}

char * CMySQLMan::GetClientInfo()
{
 return const_cast<char *>(mysql_get_client_info());
}

char* CMySQLMan::GetHostInfo()
{
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return NULL;
 }
 return const_cast<char *>(mysql_get_host_info(pMySql));
}

int CMySQLMan::GetProtocolInfo()
{
 int iRet = 0;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return NULL;
 }
 iRet = mysql_get_proto_info(pMySql);
 SetIdleMysql(pMySql);

 return iRet;
}

char* CMySQLMan::GetServerInfo()
{
 static char szRet[1024];
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return NULL;
 }
 _tcscpy(szRet, const_cast<char *>(mysql_get_server_info(pMySql)));
 SetIdleMysql(pMySql);

 return szRet;
}

char* CMySQLMan::GetState()
{
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return NULL;
 }
 static char szRet[1024];
 _tcscpy(szRet,const_cast<char *>(mysql_stat(pMySql)));
 SetIdleMysql(pMySql);

 return szRet;
}

bool CMySQLMan::SetCharset()
{
 bool bRet = false;
 char szSql[50];
 strcpy(szSql, "set names gb2312");
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if (mysql_query(pMySql, szSql))
  bRet = true;
 SetIdleMysql(pMySql);

 return bRet;
}

//LOCK TABLES tbl1 READ, tbl2 WRITE
bool CMySQLMan::LockTable(const char *TableName, const char *Priority)
{
 bool bRet = false;
 char szSql[50];
 sprintf(szSql, "LOCK TABLES %s %s", TableName, Priority);
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if (mysql_query(pMySql, szSql))
  bRet = true;
 SetIdleMysql(pMySql);

 return bRet;
}

bool CMySQLMan::UnlockTable()
{
 bool bRet = false;
 MYSQL *pMySql = GetIdleMySql();
 if (pMySql == NULL)
 {
  return false;
 }
 if(mysql_query(pMySql,"UNLOCK TABLES"))
  bRet = true;
 SetIdleMysql(pMySql);

 return bRet;

}

 



]]>
|络字节序与L字节?/title><link>http://www.shnenglu.com/aurain/archive/2008/02/18/42865.html</link><dc:creator>?/dc:creator><author>?/author><pubDate>Mon, 18 Feb 2008 03:17:00 GMT</pubDate><guid>http://www.shnenglu.com/aurain/archive/2008/02/18/42865.html</guid><wfw:comment>http://www.shnenglu.com/aurain/comments/42865.html</wfw:comment><comments>http://www.shnenglu.com/aurain/archive/2008/02/18/42865.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/aurain/comments/commentRss/42865.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aurain/services/trackbacks/42865.html</trackback:ping><description><![CDATA[不同的CPU有不同的字节序类?nbsp;q些字节序是指整数在内存中保存的序 q个叫做L?nbsp;<br>最常见的有两种<br>1Q?nbsp;Little endianQ将低序字节存储在v始地址<br>2Q?nbsp;Big endianQ将高序字节存储在v始地址<br><br>LE little-endian <br>最W合人的思维的字节序 <br>地址低位存储值的低位 <br>地址高位存储值的高位 <br>怎么讲是最W合人的思维的字节序Q是因ؓ从h的第一观感来说 <br>低位值小Q就应该攑֜内存地址的地方Q也卛_存地址低位 <br>反之Q高位值就应该攑֜内存地址大的地方Q也卛_存地址高位 <br><br>BE big-endian <br>最直观的字节序 <br>地址低位存储值的高位 <br>地址高位存储值的低位 <br>Z么说直观Q不要考虑对应关系 <br>只需要把内存地址从左到右按照׃到高的顺序写?nbsp;<br>把值按照通常的高位到低位的顺序写?nbsp;<br>两者对照,一个字节一个字节的填充q去 <br><br>例子Q在内存中双?x01020304(DWORD)的存储方?nbsp;<br><br>内存地址 <br>4000 4001 4002 4003 <br>LE 04 03 02 01 <br>BE 01 02 03 04 <br><br>例子Q如果我们将0x1234abcd写入C0x0000开始的内存中,则结果ؓ<br>      big-endian  little-endian<br>0x0000  0x12      0xcd<br>0x0001  0x23      0xab<br>0x0002  0xab      0x34<br>0x0003  0xcd      0x12<br>x86pdCPU都是little-endian的字节序. <br><br>|络字节序是TCP/IP中规定好的一U数据表C格式,它与具体的CPUcd、操作系l等无关Q从而可以保证数据在不同L之间传输时能够被正确解释。网l字节顺序采用big endian排序方式?br><br>Zq行转换 bsd socket提供了{换的函数 有下面四?br>htons 把unsigned shortcd从主机序转换到网l序<br>htonl 把unsigned longcd从主机序转换到网l序<br>ntohs 把unsigned shortcd从网l序转换C机序<br>ntohl 把unsigned longcd从网l序转换C机序<br><br>在用little endian的系l中 q些函数会把字节序进行{?nbsp;<br>在用big endiancd的系l中 q些函数会定义成I宏<br><br>同样 在网l程序开发时 或是跨^台开发时 也应该注意保证只用一U字节序 不然两方的解释不一样就会生bug.<br><br>注:<br>1、网l与L字节转换函数:htons ntohs htonl ntohl (s 是short l是long h是host n是network)<br>2、不同的CPU上运行不同的操作pȝQ字节序也是不同的,参见下表?br>处理?nbsp;   操作pȝ    字节排序<br>Alpha    全部    Little endian<br>HP-PA    NT    Little endian<br>HP-PA    UNIX    Big endian<br>Intelx86    全部    Little endian <-----x86pȝ是小端字节序pȝ<br>Motorola680x()    全部    Big endian<br>MIPS    NT    Little endian<br>MIPS    UNIX    Big endian<br>PowerPC    NT    Little endian<br>PowerPC    非NT    Big endian  <-----PPCpȝ是大端字节序pȝ<br>RS/6000    UNIX    Big endian<br>SPARC    UNIX    Big endian<br>IXP1200 ARM核心    全部    Little endian <br><br> <p>下面是一个检验本机字节序的简便方法:</p> <p>//判断本机的字节序<br>//q回true表ؓ段序。返回false表示为大D序<br><font color=#0000ff>bool am_little_endian ()<br>{<br> unsigned short i=1;<br> return (int)*((char *)(&i)) ? true : false;<br>}<br>int main()<br>{<br>  if(am_little_endian())<br> {<br>           printf("本机字节序ؓ段?\n");<br> }<br> else<br> {<br>          printf("本机字节序ؓ大段?\n");<br> }<br>        return 0;<br>}</font></p> <img src ="http://www.shnenglu.com/aurain/aggbug/42865.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aurain/" target="_blank">?/a> 2008-02-18 11:17 <a href="http://www.shnenglu.com/aurain/archive/2008/02/18/42865.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linuxpȝ环境下的Socket~程详细解析http://www.shnenglu.com/aurain/archive/2008/01/18/socket.html?/dc:creator>?/author>Fri, 18 Jan 2008 01:41:00 GMThttp://www.shnenglu.com/aurain/archive/2008/01/18/socket.htmlhttp://www.shnenglu.com/aurain/comments/41397.htmlhttp://www.shnenglu.com/aurain/archive/2008/01/18/socket.html#Feedback0http://www.shnenglu.com/aurain/comments/commentRss/41397.htmlhttp://www.shnenglu.com/aurain/services/trackbacks/41397.html什么是Socket

  Socket接口?span>TCP/IP|络?span>APIQ?span>Socket接口定义了许多函数或例程Q程序员可以用它们来开?span>TCP/IP|络上的应用E序。要?span>Internet上的TCP/IP|络~程Q必ȝ?span>Socket接口?span>

  Socket接口设计者最先是接口放?span>Unix操作pȝ里面的。如果了?span>Unixpȝ的输入和输出的话Q就很容易了?span>Socket了。网l的Socket数据传输是一U特D的I/OQ?span>Socket也是一U文件描q符?span>Socket也具有一个类g打开文g的函数调?span>Socket()Q该函数q回一个整型的Socket描述W,随后的连接徏立、数据传输等操作都是通过?span>Socket实现的。常用的Socketcd有两U:式SocketQ?span>SOCK_STREAMQ和数据报式SocketQ?span>SOCK_DGRAMQ。流式是一U面向连接的SocketQ针对于面向q接?span>TCP服务应用Q数据报?span>Socket是一U无q接?span>SocketQ对应于无连接的UDP服务应用?span>

  Socket建立

  Z建立SocketQ程序可以调?span>socket函数Q该函数q回一个类g文g描述W的句柄?span>socket函数原型为:

  int socket(int domain, int type, int protocol);

  domain指明所使用?span>协议族,通常?span>AF_INETQ表C?span>互联|?/span>协议族(TCP/IP协议族)Q?span>type参数指定socket的类型:SOCK_STREAM ?span>SOCK_DGRAMQ?span>Socket接口q定义了原始SocketQ?span>SOCK_RAWQ,允许E序使用低层协议Q?span>protocol通常赋?span>"0"Q表C根?span>type来自动选择协议Q?span>socket()调用q回一个整?span>socket描述W,你可以在后面的调用用它?/span>

  Socket描述W是一个指向内部数据结构的指针Q它指向描述W表入口。调?span>Socket函数Ӟsocket执行体将建立一?span>SocketQ实际上"建立一?span>Socket"意味着Z?span>Socket数据l构分配存储I间?span>Socket执行体ؓ你管理描q符表?/span>

  两个|络E序之间的一个网l连接包括五U信息:通信协议、本地协议地址、本C机端口、远端主机地址和远端协议端口?span>Socket数据l构中包含这五种信息?span>

  Socket配置

  通过socket函数调用q回一?span>socket描述W后Q在使用socketq行|络传输以前Q必配|该socket。面向连接的socket客户端通过调用connect函数?span>socket数据l构中保存本地和q端信息。无q接socket的客L和服务端以及面向q接socket的服务端通过调用bind函数来配|本C息?span>
bind函数?span>socket与本Z的一个端口相兌Q随后你可以在该端口监听服务请求?span>bind函数原型为:

  

int bind(int sockfd,struct sockaddr *my_addr, int addrlen);
sockfd
是调?span>socket函数q回?span>socket描述W?span>,

my_addr是一个指向包含有本机IP地址及端口号{信息的sockaddrcd的指针;

addrlen常被讄?span>sizeof(struct sockaddr)?span>
  struct sockaddrl构cd是用来保?span>socket信息的:
  struct sockaddr {
   unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14
字节的协议地址 */
};
  sa_family一般ؓAF_INETQ代?span>InternetQ?span>TCP/IPQ地址族;sa_data
则包含该socket?span>IP地址和端口号?span>
  另外q有一U结构类型:
  struct sockaddr_in {
   short int sin_family; /* 地址?span> */
   unsigned short int sin_port; /* 端口?span> */
   struct in_addr sin_addr; /* IP地址 */
   unsigned char sin_zero[8]; /* 填充0 以保持与struct sockaddr同样大小 */
  };

  q个l构更方便用?span>sin_zero用来?span>sockaddr_inl构填充Cstruct sockaddr同样的长度,可以?span>bzero()?span>memset()函数其|ؓ零。指?span>sockaddr_in 的指针和指向sockaddr的指针可以相互{换,q意味着如果一个函数所需参数cd?span>sockaddrӞ你可以在函数调用的时候将一个指?span>sockaddr_in的指针{换ؓ指向sockaddr的指针;或者相反?span>

  使用bind函数Ӟ可以用下面的赋值实现自动获得本?span>IP地址和随取一个没有被占用的端口号Q?span>

  my_addr.sin_port = 0; /* pȝ随机选择一个未被用的端口?span> */
  my_addr.sin_addr.s_addr = INADDR_ANY; /* 填入本机IP地址 */
通过?span>my_addr.sin_port|ؓ0Q函C自动Z选择一个未占用的端口来使用。同P通过?span>my_addr.sin_addr.s_addr|ؓINADDR_ANYQ系l会自动填入本机IP地址?/span>

  注意在?span>bind函数是需要将sin_port?span>sin_addr转换成ؓ|络字节优先序Q?span>sin_family则不需要{换?/span>

  计算机数?span>存储有两U字节优先顺序:高位字节优先和低位字节优先?span>Internet上数据以高位字节优先序在网l上传输Q所以对于在内部是以低位字节优先方式存储数据的机器,?span>Internet上传输数据时需要进行{换,否则׃出现数据不一致?/span>

  下面是几个字节顺序{换函敎ͼ

·htonl()Q把32位gL字节序{换成|络字节?span>
·htons()
Q把16位gL字节序{换成|络字节?span>
·ntohl()Q把32位g|络字节序{换成L字节?span>
·ntohs()Q把16位g|络字节序{换成L字节?span>

  bind()函数在成功被调用时返?span>0Q出现错误时q回"-1"q将errno|ؓ相应的错误号。需要注意的是,在调?span>bind函数时一般不要将端口L为小?span>1024的|因ؓ1?span>1024是保留端口号Q你可以选择大于1024中的M一个没有被占用的端口号?/span>

q接建立

面向q接的客L序?span>connect函数来配|?span>socketq与q端服务?/span>建立一?span>TCPq接Q其函数原型为:

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
sockfd
?span>socket函数q回?span>socket描述W;serv_addr是包含远端主?span>IP地址和端口的指针Q?span>addrlen是远端地址l构的长?span>(sizeof(struct sockaddr))?span>connect函数在出现错误时q回-1Qƈ且设|?span>errno为相应的错误码。进行客LE序设计无须调用bind()Q因U情况下只需知道目的机器?span>IP地址Q而客户通过哪个端口?span>服务?/span>建立q接q不需要关心,socket执行体ؓ你的E序自动选择一个未被占用的端口Qƈ通知你的E序数据什么时候到打断口?/span>

  connect函数启动和远端主机的直接q接。只有面向连接的客户E序使用socket时才需要将?span>socket与远端主机相q。无q接协议从不建立直接q接。面向连接的服务器也从不启动一个连接,它只是被动的在协议端口监听客Lh?span>

  listen函数?span>socket处于被动的监听模式,qؓ?span>socket建立一个输入数据队列,到辄服务h保存在此队列中,直到E序处理它们?/span>

  int listen(int sockfdQ?span> int backlog);

  sockfd?span>Socketpȝ调用q回?span>socket 描述W;backlog指定在请求队列中允许的最大请求数Q进入的q接h在队列中等?span>accept()它们Q参考下文)?span>backlog寚w列中{待服务的请求的数目q行了限Ӟ大多数系l缺省gؓ20。如果一个服务请求到来时Q输入队列已满,?span>socket拒l连接请求,客户收C个出错信息?/span>

  当出现错误时listen函数q回-1Qƈ|相应的errno错误码?/span>

  accept()函数让服务器接收客户的连接请求。在建立好输入队列后Q服务器p?span>accept函数Q然后睡眠ƈ{待客户的连接请求?/span>

  int accept(int sockfd, void *addr, int *addrlen);

  sockfd是被监听?span>socket描述W,addr通常是一个指?span>sockaddr_in变量的指针,该变量用来存放提接请求服务的L的信息(某台L从某个端口发hQ;addrlen通常Z个指向gؓsizeof(struct sockaddr_in)的整型指针变量。出现错误时accept函数q回-1q置相应?span>errno倹{?/span>

  首先Q当accept函数监视?span>socket收到q接hӞsocket执行体将建立一个新?span>socketQ执行体这个新socket和请求连接进E的地址联系hQ收到服务请求的初始socket仍可以l在以前?span> socket上监听,同时可以在新?span>socket描述W上q行数据传输操作?span>

  数据传输

  send()?span>recv()q两个函数用于面向连接的socket上进行数据传输?span>

  send()函数原型为:

  int send(int sockfd, const void *msg, int len, int flags);
sockfd
是你想用来传输数据的socket描述W;msg是一个指向要发送数据的指针Q?span>len
是以字节为单位的数据的长度;flags一般情况下|ؓ0Q关于该参数的用法可参照man手册Q?span>

  send()函数q回实际上发送出的字节数Q可能会于你希望发送的数据。在E序中应该将send()的返回gƲ发送的字节数进行比较。当send()q回glen不匹配时Q应该对q种情况q行处理?span>
char *msg = "Hello!";
int len, bytes_sent;
……
len = strlen(msg);
bytes_sent = send(sockfd, msg,len,0);
……
  recv()函数原型为:

  int recv(int sockfd,void *buf,int len,unsigned int flags);

  sockfd是接受数据的socket描述W;buf 是存放接收数据的~冲区;len是缓冲的长度?span>Flags也被|ؓ0?span>recv()q回实际上接收的字节敎ͼ当出现错误时Q返?span>-1q置相应?span>errno倹{?span>

  sendto()?span>recvfrom()用于在无q接的数据报socket方式下进行数据传输。由于本?span>socketq没有与q端机器建立q接Q所以在发送数据时应指明目的地址?span>
  sendto()函数原型为:
  int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);

  该函数比send()函数多了两个参数Q?span>to表示目地机的IP地址和端口号信息Q?span>tolen常常被赋gؓsizeof (struct sockaddr)?span>sendto 函数也返回实际发送的数据字节长度或在出现发送错误时q回-1?span>

  recvfrom()函数原型为:

  int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);

  from是一?span>struct sockaddrcd的变量,该变量保存源机的IP地址及端口号?span>fromlen常置?span>sizeof (struct sockaddr)。当recvfrom()q回Ӟfromlen包含实际存入from中的数据字节数?span>recvfrom()函数q回接收到的字节数或当出现错误时q回-1Qƈ|相应的errno?span>

  如果你对数据?span>socket调用?span>connect()函数Ӟ你也可以利用send()?span>recv()q行数据传输Q但?span>socket仍然是数据报socketQƈ且利用传输层?span>UDP服务。但在发送或接收数据报时Q内怼自动Z加上目地和源地址信息?span>

  l束传输

  当所有的数据操作l束以后Q你可以调用close()函数来释放该socketQ从而停止在?span>socket上的M数据操作Q?span>

  close(sockfd);

  你也可以调用shutdown()函数来关闭该socket。该函数允许你只停止在某个方向上的数据传输,而一个方向上的数据传输l进行。如你可以关闭某socket的写操作而允许l在?span>socket上接受数据,直至d所有数据?span>

  int shutdown(int sockfd,int how);

  sockfd是需要关闭的socket的描q符。参?span> how允许?span>shutdown操作选择以下几种方式Q?span>
·0-------不允许l接收数?span>
·1-------不允许l发送数?span>
·2-------不允许l发送和接收数据Q?span>
·均ؓ不允许则调用close()

  shutdown在操作成功时q回0Q在出现错误时返?span>-1q置相应errno?span>

 

面向q接?span>Socket实例

  代码实例中的服务器通过socketq接向客L发送字W串"Hello, you are connected!"。只要在服务器上q行该服务器软gQ在客户端运行客戯YӞ客户端就会收到该字符丌Ӏ?span>

  该服务器软g代码如下Q?span>

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define SERVPORT 3333 /*
服务器监听端口号 */
#define BACKLOG 10 /*
最大同时连接请求数 */
main()
{
int sockfd,client_fd; /*sock_fd
Q监?span>socket
Q?span>client_fdQ数据传?span>socket */
 struct sockaddr_in my_addr; /* 本机地址信息 */
 struct sockaddr_in remote_addr; /* 客户端地址信息 */
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  perror("socket创徏出错Q?span>"); exit(1);
}
my_addr.sin_family=AF_INET;
 my_addr.sin_port=htons(SERVPORT);
 my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero),8);
 if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) \
   == -1) {
perror("bind
出错Q?span>");
exit(1);
}
 if (listen(sockfd, BACKLOG) == -1) {
perror("listen
出错Q?span>");
exit(1);
}
while(1) {
  sin_size = sizeof(struct sockaddr_in);
  if ((client_fd = accept(sockfd, (struct sockaddr *)&remote_addr, \
  &sin_size)) == -1) {
perror("accept
出错");
continue;
}
  printf("received a connection from %s\n", inet_ntoa(remote_addr.sin_addr));
  if (!fork()) { /* 子进E代码段 */
   if (send(client_fd, "Hello, you are connected!\n", 26, 0) == -1)
   perror("send出错Q?span>");
close(client_fd);
exit(0);
}
  close(client_fd);
  }
 }
}

  服务器的工作程是这LQ首先调?span>socket函数创徏一?span>SocketQ然后调?span>bind函数其与本机地址以及一个本地端口号l定Q然后调?span>listen在相应的socket上监听,?span>accpet接收C个连接服务请求时Q将生成一个新?span>socket。服务器昄该客h?span>IP地址Qƈ通过新的socket向客L发送字W串"HelloQ?span>you are connected!"。最后关闭该socket?/span>

  代码实例中的fork()函数生成一个子q程来处理数据传输部分,fork()语句对于子进E返回的gؓ0。所以包?span>fork函数?span>if语句是子q程代码部分Q它?span>if语句后面的父q程代码部分是ƈ发执行的?span>

  客户端程序代码如下:

#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define SERVPORT 3333
#define MAXDATASIZE 100 /*
每次最大数据传输量 */
main(int argc, char *argv[]){
 int sockfd, recvbytes;
 char buf[MAXDATASIZE];
 struct hostent *host;
 struct sockaddr_in serv_addr;
 if (argc < 2) {
fprintf(stderr,"Please enter the server's hostname!\n");
exit(1);
}
 if((host=gethostbyname(argv[1]))==NULL) {
herror("gethostbyname
出错Q?span>");
exit(1);
}
 if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket
创徏出错Q?span>");
exit(1);
}
 serv_addr.sin_family=AF_INET;
 serv_addr.sin_port=htons(SERVPORT);
 serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
 bzero(&(serv_addr.sin_zero),8);
 if (connect(sockfd, (struct sockaddr *)&serv_addr, \
   sizeof(struct sockaddr)) == -1) {
perror("connect
出错Q?span>");
exit(1);
}
 if ((recvbytes=recv(sockfd, buf, MAXDATASIZE, 0)) ==-1) {
perror("recv
出错Q?span>");
exit(1);
}
 buf[recvbytes] = '\0';
 printf("Received: %s",buf);
 close(sockfd);
}

 

客户端程序首先通过服务器域名获得服务器?span>IP地址Q然后创Z?span>socketQ调?span>connect函数与服务器建立q接Q连接成功之后接收从服务器发送过来的数据Q最后关?span>socket?/span>

  函数gethostbyname()是完成域名{换的。由?span>IP地址难以记忆和读写,所以ؓ了方便,Z常常用域名来表示LQ这需要进行域名和IP地址的{换。函数原型ؓQ?/span>


  struct hostent *gethostbyname(const char *name);
  函数q回?span>hosten
的结构类型,它的定义如下Q?span>
  struct hostent {
  char *h_name; /* L的官方域?span> */
   char **h_aliases; /* 一个以NULLl尾的主机别名数l?span> */
   int h_addrtype; /* q回的地址cdQ在Internet环境下ؓAF-INET */
  int h_length; /* 地址的字节长?span> */
   char **h_addr_list; /* 一个以0l尾的数l,包含该主机的所有地址*/
  };
  #define h_addr h_addr_list[0] /*?span>h-addr-list中的W一个地址*/

  ?span> gethostname()调用成功Ӟq回指向struct hosten的指针,当调用失败时q回-1。当调用gethostbynameӞ你不能?span>perror()函数来输出错误信息,而应该?span>herror()函数来输出?span>

  无连接的客户/服务器程序的在原理上和连接的客户/服务器是一LQ两者的区别在于无连接的客户/服务器中的客户一般不需要徏立连接,而且在发送接收数据时Q需要指定远端机的地址?span>

  d和非d

  d函数在完成其指定的Q务以前不允许E序调用另一个函数。例如,E序执行一个读数据的函数调用时Q在此函数完成读操作以前不会执行下一E序语句。当服务器运行到accept语句Ӟ而没有客戯接服务请求到来,服务器就会停止在accept语句上等待连接服务请求的到来。这U情늧为阻塞(blockingQ。而非d操作则可以立卛_成。比如,如果你希望服务器仅仅注意查是否有客户在等待连接,有就接受q接Q否则就l箋做其他事情,则可以通过?span>Socket讄为非d方式来实现。非dsocket在没有客户在{待时就?span>accept调用立即q回?span>
  #include
  #include
  ……
sockfd = socket(AF_INET,SOCK_STREAM,0);
fcntl(sockfd,F_SETFL,O_NONBLOCK)
Q?span>
……

  通过讄socket为非d方式Q可以实?span>"轮询"若干Socket。当企图从一个没有数据等待处理的非阻?span>Socketd数据Ӟ函数立卌回,q回gؓ-1Qƈ|?span>errnogؓEWOULDBLOCK。但是这U?span>"轮询"CPU处于忙等待方式,从而降低性能Q浪费系l资源。而调?span>select()会有效地解决q个问题Q它允许你把q程本n挂v来,而同时ɾpȝ内核监听所要求的一l文件描q符的Q何活动,只要认在Q何被监控的文件描q符上出现活动,select()调用返回指C文g描述W已准备好的信息Q从而实CE选出随机的变化,而不必由q程本n对输入进行测试而浪?span>CPU开销?span>select函数原型?span>:
int select(int numfds,fd_set *readfds,fd_set *writefdsQ?span>
fd_set *exceptfds,struct timeval *timeout);

  其中readfds?span>writefds?span>exceptfds分别是被select()监视的读、写和异常处理的文g描述W集合。如果你希望定是否可以从标准输入和某个socket描述W读取数据,你只需要将标准输入的文件描q符0和相应的sockdtfd加入?span>readfds集合中;numfds的值是需要检查的L最高的文g描述W加1Q这个例子中numfds的值应?span>sockfd+1Q当selectq回Ӟreadfds被修改Q指C某个文件描q符已经准备被读取,你可以通过FD_ISSSET()来测试。ؓ了实?span>fd_set中对应的文g描述W的讄、复位和试Q它提供了一l宏Q?span>
  FD_ZERO(fd_set *set)----清除一个文件描q符集;
  FD_SET(int fd,fd_set *set)----一个文件描q符加入文g描述W集中;
  FD_CLR(int fd,fd_set *set)----一个文件描q符从文件描q符集中清除Q?span>
  FD_ISSET(int fd,fd_set *set)----试判断是否文件描q符被置位?span>
  Timeout参数是一个指?span>struct timevalcd的指针,它可以select()在等?span>timeout长时间后没有文g描述W准备好卌回?span>struct timeval数据l构为:
  struct timeval {
   int tv_sec; /* seconds */
   int tv_usec; /* microseconds */ };

  POP3客户端实?span>

  下面的代码实例基?span>POP3的客户协议,与邮件服务器q接q取回指定用户帐L邮g。与邮g服务器交互的命o存储在字W串数组POPMessage中,E序通过一?span>do-while循环依次发送这些命令?span>

#include
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define POP3SERVPORT 110
#define MAXDATASIZE 4096

main(int argc, char *argv[]){
int sockfd;
struct hostent *host;
struct sockaddr_in serv_addr;
char *POPMessage[]={
"USER userid\r\n",
"PASS password\r\n",
"STAT\r\n",
"LIST\r\n",
"RETR 1\r\n",
"DELE 1\r\n",
"QUIT\r\n",
NULL
};
int iLength;
int iMsg=0;
int iEnd=0;
char buf[MAXDATASIZE];

if((host=gethostbyname("your.server"))==NULL) {
perror("gethostbyname error");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1){
perror("socket error");
exit(1);
}
serv_addr.sin_family=AF_INET;
serv_addr.sin_port=htons(POP3SERVPORT);
serv_addr.sin_addr = *((struct in_addr *)host->h_addr);
bzero(&(serv_addr.sin_zero),8);
if (connect(sockfd, (struct sockaddr *)&serv_addr,sizeof(struct sockaddr))==-1){
perror("connect error");
exit(1);
}

do {
send(sockfd,POPMessage[iMsg],strlen(POPMessage[iMsg]),0);
printf("have sent: %s",POPMessage[iMsg]);

iLength=recv(sockfd,buf+iEnd,sizeof(buf)-iEnd,0);
iEnd+=iLength;
buf[iEnd]='\0';
printf("received: %s,%d\n",buf,iMsg);

iMsg++;
} while (POPMessage[iMsg]);

close(sockfd);
}

 



]]>
inet_addr函数的实?/title><link>http://www.shnenglu.com/aurain/archive/2007/12/05/37855.html</link><dc:creator>?/dc:creator><author>?/author><pubDate>Wed, 05 Dec 2007 07:58:00 GMT</pubDate><guid>http://www.shnenglu.com/aurain/archive/2007/12/05/37855.html</guid><wfw:comment>http://www.shnenglu.com/aurain/comments/37855.html</wfw:comment><comments>http://www.shnenglu.com/aurain/archive/2007/12/05/37855.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.shnenglu.com/aurain/comments/commentRss/37855.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/aurain/services/trackbacks/37855.html</trackback:ping><description><![CDATA[<p>输入是点分的IP地址格式Q如A.B.C.D)的字W串Q从该字W串中提取出每一部分Q{换ؓULONG,假设得到4个ULONG型的A,B,C,D,<br>ulAddressQULONG型)是{换后的结果,<br>ulAddress = D<<24 + C<<16 + B<<8 + A(|络字节序)Q即inet_addr(const char *)的返回结?br>另外Q我们也可以得到把该IP转换Z机序的结果,转换Ҏ一?br>A<<24 + B<<16 + C<<8 + D<font style="BACKGROUND-COLOR: #cce8cf"></font></p> <img src ="http://www.shnenglu.com/aurain/aggbug/37855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/aurain/" target="_blank">?/a> 2007-12-05 15:58 <a href="http://www.shnenglu.com/aurain/archive/2007/12/05/37855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <p>лǵվܻԴȤ</p> <a href="http://www.shnenglu.com/" title="精品视频久久久久">精品视频久久久久</a> <div class="friend-links"> </div> </div> </footer> <a href="http://www.dgjiajun.net.cn" target="_blank">XxŷʸƷþþþþ</a>| <a href="http://www.650qq.cn" target="_blank">ɫۺϾþĻ</a>| <a href="http://www.davidgroup.com.cn" target="_blank">ھƷžžþþþƷ</a>| <a href="http://www.manini.cn" target="_blank">99þþùƷ޿</a>| <a href="http://www.nicemom.cn" target="_blank">þ99Ʒþþþþ</a>| <a href="http://www.jingxuan001.cn" target="_blank">þǿdŮվ</a>| <a href="http://www.wbyyd.cn" target="_blank">þˬˬƬAV鷳</a>| <a href="http://www.kwk9605.cn" target="_blank">þ޾ƷAV</a>| <a href="http://www.17740.cn" target="_blank">þ97þ97Ʒӿ</a>| <a href="http://www.cz27b1.cn" target="_blank">ۺ˾þôý</a>| <a href="http://www.taphha.cn" target="_blank">þѹƷһ</a>| <a href="http://www.hbxasn.cn" target="_blank">þֹۺ޾Ʒ</a>| <a href="http://www.linuxls.cn" target="_blank">޹þþþþþ</a>| <a href="http://www.par354.cn" target="_blank">ѾƷպȾþ</a>| <a href="http://www.baolaiqi.com.cn" target="_blank">ݺɫþۺ</a>| <a href="http://www.ecscrm.com.cn" target="_blank">ŷһþþþþþô</a>| <a href="http://www.odostudio.cn" target="_blank">ƷþþӰ</a>| <a href="http://www.logeng.cn" target="_blank">ŷ˾þۺ</a>| <a href="http://www.vanblog.cn" target="_blank">ƷѸþ</a>| <a href="http://www.rainbow-city.cn" target="_blank">޹뾫ƷŮ˾þþò </a>| <a href="http://www.gmve.cn" target="_blank">99þˬ޾ƷŮ</a>| <a href="http://www.drxt.com.cn" target="_blank">ձƷһþþ</a>| <a href="http://www.jupucha.com.cn" target="_blank">þùĻ</a>| <a href="http://www.52cxw.cn" target="_blank">޾ƷĻþò</a>| <a href="http://www.jxsrgh.com.cn" target="_blank">þٸ۲AV</a>| <a href="http://www.2782yh.cn" target="_blank">þþþĻ</a>| <a href="http://www.bassaphoto.cn" target="_blank">þþþþþAv</a>| <a href="http://www.job158.cn" target="_blank">޹ŮƷþþþá</a>| <a href="http://www.i501.cn" target="_blank">þþƷƷʢۿ</a>| <a href="http://www.yy2b.cn" target="_blank">˾þóۺӰԺ</a>| <a href="http://www.52maila.cn" target="_blank">þþWWW</a>| <a href="http://www.hongneiku.cn" target="_blank">þþþһƷ</a>| <a href="http://www.ejectorpin.cn" target="_blank">ƷŷƬþùŷ... ƷŷƬþùŷ </a>| <a href="http://www.n-hao.cn" target="_blank">þþþþþþ66ƷƬ</a>| <a href="http://www.eobt.cn" target="_blank">þþþֻоƷ </a>| <a href="http://www.whbgjj1.cn" target="_blank">պþþþƷӰԺҳ</a>| <a href="http://www.wxpie.cn" target="_blank">þ91˳ɵӰվ</a>| <a href="http://www.reducki.cn" target="_blank">AVþþþò</a>| <a href="http://www.qnzj.org.cn" target="_blank">þ޹ŷ޾Ʒһ</a>| <a href="http://www.cybook.com.cn" target="_blank">99þù޸ۿ2024</a>| <a href="http://www.grayhound.cn" target="_blank">ѹ99þþ㽶</a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>