导读:
。难道要去这个侦听的套接字去接收消息,发送文件吗?那怎么并发。如果传送一个大文件的时候是不是其它的连接请求都会在等呢?不是,侦听套接字是专门为接收客户机连接请求,完成3次握手操作而用的,所以tcp协议不能使用这个套接字来描述实际的连接。
函数Accept可以返回一个socket,那看看它返回的这个套接字程序是不是可用。它在msdn上的解释为The acceptfunction permits an incoming connection attempt on a socket。它的功能是从侦听套接字的完成连接队列中接收一个连接。如果完成连接队列为空,那么这个进行就会睡眠。为什么要用accept呢?它返回的socket与侦听用的socket有什么不同呢?实际上这个accept返回的套接字为connected socket 。它与侦听套接字是完全不同的。一个服务器进程通常只能创建一个侦听套接字,在服务器的进程的活动期间,它只用来接收客户端的连接请求。对于每个过来的连接Accept函数都会返回一个连接套接字。客户机与服务器的真正通信操作在accept返回的套接字上进行。当通讯完毕后,服务器或客户机会关闭这个socket连接。那有谁来关闭这个套接字是合适的呢?服务器?客户机?我现在也拿不太准。还是一会做个实验试试吧。暂且一放。
这样或许离我们的要求近一点了。有了侦听。再获得实际连接的套接字去做实际的操作然后服务器再去侦听。嗯。想想这样是符合逻辑了。这是个循环操作,并且是个死循环,因为服务器通常是7*24小时在工作的。那把accept放到一个死循环中去吧。像下面这样:
for(;;) {
NewSock = accept(pNewSockInfo->Sock,(struct sockaddr *)&(pNewSockInfo->ssin),&(pNewSockInfo->NameLen));
if(NewSock WriteLog2(ERRORLOG,AnsiToUnicode(__FILE__),__LINE__,
_T("Accept Error ,GetLastError=[%ld]"), GetLastError());
closesocket(NewSock);
g_TransEnd = TRUE;
continue;
}
Recv (…..)
….
}
代码片断,太懒了。每次贴上的代码都要改一下才能使用。
从程序上来看,离要求还要差一点。我每次使用accept后是不是要继续向下执行啊。如果recv(……)这个函数后面跟着一大堆代码程序肯定会是在执行完这堆代码后才能再去accept。那在执行这一大堆代码的时候来了10个连接,那这10个是不是都在等着你执行完了后才能被accept函数从队列中取出来啊。那一个socket在工作让其它的都停止是不是有些霸道了?
多线程。个人觉得多线程与套接字分不开。每次accept成功后,启动一个新线程,让这个新线程去做你想做的工作。然后让accept继续去从队列中去等着取套接字去。
至此服务器端的程序可以了。完了后总得测试一个吧。代码如下:
服务器端代码
// Study_Socket.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#pragma comment(lib, "ws2_32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
struct sockaddr_in ssin;
WSADATA wsaData;
int nNameLen = 0;
SOCKET Sock;
SOCKET NewSock;
// 版本协商
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if (iResult != 0) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return 0;
}
ZeroMemory( &ssin , sizeof(ssin) );
ssin.sin_family = AF_INET;
// 设置套接字选项
ssin.sin_addr.s_addr = inet_addr( "172.28.14.152" );
ssin.sin_port = htons( 8848 );
if ( ( Sock = socket ( AF_INET , SOCK_STREAM , IPPROTO_TCP ) ) //WriteLog2(ERRORLOG,AnsiToUnicode(__FILE__),__LINE__,
// _T("Socket Create Error ,GetLastError=[%ld]"),GetLastError());
exit(0);
}
nNameLen = sizeof(ssin);
if ( bind ( Sock , (struct sockaddr*) &ssin , nNameLen ) //WriteLog2(ERRORLOG,AnsiToUnicode(__FILE__),__LINE__,
// _T("Bind Error ,GetLastError=[%ld]"),GetLastError() );
exit(-1);
}
if ( listen ( Sock , 50 ) //WriteLog2(ERRORLOG,AnsiToUnicode(__FILE__),__LINE__,
// _T("Listen Error ,GetLastError=[%ld]"),GetLastError() );
exit(-1);
}
for(;;) {
NewSock = accept(Sock,(struct sockaddr *)&(ssin),&(nNameLen));
if(NewSock //WriteLog2(ERRORLOG,AnsiToUnicode(__FILE__),__LINE__,
// _T("Accept Error ,GetLastError=[%ld]"), GetLastError());
closesocket(NewSock);
continue;
}
else
printf ("I have receive a message from client");
}
// 释放资源
WSACleanup();
return 0;
}
客户端代码
// Study_Socket_Client.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#pragma comment(lib, "ws2_32.lib")
BOOL setWinSock(SOCKET &s,char *ip_addr,u_short port_NO);
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
SOCKET sock;
// 版本协商
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if (iResult != 0) {
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
return 0;
}
if ( TRUE == setWinSock( sock,"172.28.14.152",8848) ) {
// you can send or recv data
printf ("I have successfully connect to remote server !");
closesocket(sock);
}
else {
// write log
return 0;
}
// 释放资源
WSACleanup();
return 0;
}
// connect to remote server
BOOL setWinSock(SOCKET &s,char *ip_addr,u_short port_NO)
{
s=socket(AF_INET,SOCK_STREAM,0);
if(s // write getlasterror for get error cause
return FALSE;
}
struct sockaddr_in serveraddr;
serveraddr.sin_family=AF_INET;
serveraddr.sin_port=htons(port_NO);
serveraddr.sin_addr.S_un.S_addr=inet_addr((const char *)ip_addr);
if(connect(s,(struct sockaddr*)&serveraddr,sizeof(serveraddr)) DWORD dwErr = GetLastError();
return FALSE;
}
return TRUE;
}
当服务器端开始运行的时候,我使用netstat –na 命令可以看到应用程序确实在172.28.14.152 的8848 端口上进行侦听了。
如果运行客户端后,服务器与客户端执行情况如下。
Server
Client
有了上面这个简单的例子,是不是我们在accept后加入多线程就能做实际工作了呢?可以,但实际工作中网络的特殊情况很多。如果我们要做一个端口扫描器,给出一个地址段给出一个端口段,那我怎样扫描一下呢?现在客户端使用的是随机端口如果我想指定端口与服务器进行连接呢?如果我想使用异步socket呢?如果一个端口被其它应用程序占用了我怎样找一个可用的端口呢?…….很多问题。下面我把能想到的都做一个测试,测试中还会有其它的一些问题,有问题就解决问题吧。
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=2007294
本文转自
http://blog.csdn.net/lk_cool/archive/2008/01/01/2007294.aspx