相应的函数说明
函数定义:int listen(int s, int backlog)
函数说明:listen()用来等待参数s的socket连线。参数backlog指定同时能处理的最大连接要求,如果连接数目达到此上限则client 端将收到ECONNREFUSED的错误(请参connect())。 listen()并未开始接受连线,只是设置socket为listen模式,真正接受client()端连线的是accept()。通常listen ()会在socket()、bind()之后调用,接着才调用accept()
附加说明:listen()只适用SOCK_STREAM或SOCK_SEQPACKET的socket类型.如果socket为AF_INET则参数 backlog最大值可设到128
返回值 :成功则返回0, 失败则返回-1, 错误原因存于errno中
错误代码:EBADF 参数sockfd非合法socket处理代码
EACCESS 权限不足
EOPNOTSUPP 指定的socket并未支援listen模式
srv服务器:
1添加支持winsock的库和头文件:
#include<winsock.h>
#pragam content(l.b,"winsock.lib")
2.设定一些初始函数
SOCKET m_hSocket;
UINT m_uPORT;
sockaddr_in m_addr;
WSADATA wsadata;
WORD WversionRequest=MAKEWORD(2.0);//指定winsock版本为2.0
WSAStartup(WversionRequest,&wsadata);//启动winsock
m_hSocket=Socket(AF_INET,SOCK_STREAM,0);//创建TCP流 套接字,第三个参数一般为0表示默认TCP/IP协议
WSAAsayncSelect(m_hSocket,//异步选择模式
this->m_hWnd;//接收消息的窗口句柄
WM_SRVMSG; //指定消息
FD_ACCEPT|FD_READ|FD_WHITE|FD_CLOSE//指定接收处理的事件
);
m_uPort=8888;//指定端口
//设置套接字结构体对象
m_addr.sin_family=AF_INET;
m_addr.sin_addr.S_un.S_addr=INADDR_ANY;
m_addr.sin_port=htons(m_uPort);
band(m_hSocket,(LPSOCKADDR)m_addr,sizeof(m_addr));//绑定套接字
listen(m_hSocket,3);//进入监听状态,最后一个参数指定正在等待连接的队列的最大长度,可取1~5F_INET协议下最大128
//在FD_ACCEPT中等待对方的连接
然后在WM_SRVMSG的消息中处理相关的消息,假定WM_SRVMSG对应的函数为OnSrvMsg(WPARAM wParam,LPARAM lParam)
long OnSrvMsg(WPARAM wParam,LPARAM lParam)
{
SOCKET socket;
switch(lParam)
{
case FD_ACCEPT:
{
socket=accept(m_hSocket,NULL,NULL);//此套接字则用来与连接的客户端通信
//需要将此套接字保存起来,以后使用
. .............
break;
}
case FD_READ:
{
if(保存的某个套接字 s==wParam)
{
int len=recv(s,buf,siseof(buf),0);//接收数据存入数据缓存区,buf指接收的缓存
send(s,buf1,strlen(buf1),0);发送消息,buf1指要发送内容的缓存
}
break;
}
}
}
客户端:
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 0);
WSAStartup(wVersionRequested, &wsaData);
m_hSocket = socket(AF_INET, SOCK_STREAM, 0);
WSAAsyncSelect(m_hSocket, this->m_hWnd, WM_CLIENTMSG, FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE);
m_addr.sin_family = AF_INET;
m_addr.sin_addr.S_un.S_addr = inet_addr(“10.13.76.49”);//为一点分十进制字符串Ip
m_addr.sin_port = htons(m_uPort);
connect(m_hSocket, (LPSOCKADDR)&m_addr, sizeof(m_addr));
long OnClientMsg(WPARAM wParam, LPARAM lParam)
{
char buf[1024];
int len;
switch(lParam)
{
case FD_CONNECT:
//如果收到FD_CONNECT消息,代表连接成功
m_strShow = "连接到服务器……";
UpdateData(FALSE);
return 0;
case FD_READ:
len = recv(m_hSocket, buf, 1024, 0);
buf[len]=NULL;
m_strShow += "/r/n";
m_strShow += buf;
UpdateData(FALSE);
return 0;
case FD_WRITE:
return 0;
case FD_CLOSE:
return 0;
default:
closesocket(m_hSocket);
return 0;
}
}
对于MFC封装的CAsyncSocket则是需要包含#include<afxsock.h>
对于MFC封装的CAsyncSocket则是需要包含#include<afxsock.h>
1CAsyncSocket调用AfxSocketInit()函数初始化Winsock
2调用构造函数构造一个CAsyncSocket对象
3调用create函数创建套接字句柄
4客户端:调用connect函数想服务器发送连接 服务器:调用listen函数开始监听,一旦有连接请求调用Accept函数接受请求
5调用类成员函数执行通信和其他操作
6调用Close函数结束连接,销毁CAsyncSocket
在这个过程中也需要指定接受消息的窗口指针,在窗口类中包含自己的CAsyncSocket对象
ServerSocket.h文件
// ServerSocket.h : header file
#if !defined(AFX_SERVERSOCKET_H__B3F0ADA3_53E6_46ED_A6B8_B077056FA439__INCLUDED_)
#define AFX_SERVERSOCKET_H__B3F0ADA3_53E6_46ED_A6B8_B077056FA439__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ServerSocket.h : header file
//
class CServerDlg;
/////////////////////////////////////////////////////////////////////////////
// CServerSocket command target
class CServerSocket : public CSocket
{
// Attributes
public:
// Operations
public:
CServerSocket();
virtual ~CServerSocket();
// Overrides
public:
void Init(UINT port, CServerDlg * pDlg); // 服务器套接字初始化
CServerDlg * m_pDlg; // 调用窗口指针
UINT m_uPort; // 服务端口号
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CServerSocket)
public:
virtual void OnAccept(int nErrorCode); // 重载OnAccept消息响应
//}}AFX_VIRTUAL
// Generated message map functions
//{{AFX_MSG(CServerSocket)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
// Implementation
protected:
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SERVERSOCKET_H__B3F0ADA3_53E6_46ED_A6B8_B077056FA439__INCLUDED_)
ServerSocket.cpp文件
****// ServerSocket.cpp : implementation file
#include "stdafx.h"
#include "Server.h"
#include "ServerSocket.h"
#include "ServerDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CServerSocket
CServerSocket::CServerSocket()
{
}
CServerSocket::~CServerSocket()
{
}
// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CServerSocket, CSocket)
//{{AFX_MSG_MAP(CServerSocket)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif // 0
/////////////////////////////////////////////////////////////////////////////
// CServerSocket member functions
void CServerSocket::Init(UINT port, CServerDlg * pDlg)
{
m_uPort = port;
m_pDlg = pDlg;
this->Create(m_uPort); // 创建服务器套接字
this->Listen(); // 开始监听连接请求
m_pDlg->m_strShow = "服务器已启动……";
m_pDlg->UpdateData(FALSE);
}
void CServerSocket::OnAccept(int nErrorCode)
{
m_pDlg->ProcessPendingAccept(); // 响应Accept,调用服务器窗口的处理函数
CSocket::OnAccept(nErrorCode);
}
对话框.h文件
// ServerDlg.h : header file
//
#if !defined(AFX_SERVERDLG_H__42C424E6_5301_457B_B79E_CF503B8871E9__INCLUDED_)
#define AFX_SERVERDLG_H__42C424E6_5301_457B_B79E_CF503B8871E9__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include "ClientSocket.h"
#include "ServerSocket.h"
/////////////////////////////////////////////////////////////////////////////
// CServerDlg dialog
class CServerDlg : public CDialog
{
// Construction
public:
void ProcessPendingAccept(); // OnAccept响应处理函数
CServerSocket m_ListenSocket; // 服务器套接字监听对象
UINT m_uPort; // 服务进程端口号
void CloseSessionSocket(); // 关闭套接字会话
CPtrList m_plConn; // 已连接的客户端套接字列表
CServerDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CServerDlg)
enum { IDD = IDD_SERVER_DIALOG };
CEdit m_Show;
CString m_strShow;
CString m_strMsg;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CServerDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CServerDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton1(); // 消息发送按钮命令响应函数
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SERVERDLG_H__42C424E6_5301_457B_B79E_CF503B8871E9__INCLUDED_)
对话框CPP
// ServerDlg.cpp : implementation file
//
#include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"
#include "Msg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerDlg dialog
CServerDlg::CServerDlg(CWnd* pParent /*=NULL*/)
: CDialog(CServerDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CServerDlg)
m_strShow = _T("");
m_strMsg = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CServerDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CServerDlg)
DDX_Control(pDX, IDC_EDIT1, m_Show);
DDX_Text(pDX, IDC_EDIT1, m_strShow);
DDX_Text(pDX, IDC_EDIT2, m_strMsg);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CServerDlg, CDialog)
//{{AFX_MSG_MAP(CServerDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CServerDlg message handlers
BOOL CServerDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
AfxSocketInit(NULL); // 初始化Socket环境
m_uPort = 8888; // 初始化服务进程端口
m_ListenSocket.Init(m_uPort, this); // 初始化监听套接字
return TRUE; // return TRUE unless you set the focus to a control
}
void CServerDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CServerDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CServerDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CServerDlg::CloseSessionSocket()
{
for(POSITION pos=m_plConn.GetHeadPosition(); pos!=NULL;)
{
POSITION pos1 = pos;
CClientSocket * s = (CClientSocket*)m_plConn.GetNext(pos);
if(s->m_bClose == true)
{ // 从已连接套接字列表中移除已关闭的套接字
m_plConn.RemoveAt(pos1);
}
}
}
void CServerDlg::ProcessPendingAccept()
{
CClientSocket * pSocket = new CClientSocket(); // 新建客户端套接字
if (m_ListenSocket.Accept(*pSocket)) // 接受连接请求
{
CMsg msg; // 声明消息对象
msg.m_strMsg = "一名游客进入聊天室";
for(POSITION pos=m_plConn.GetHeadPosition(); pos!=NULL;)
{ // 向客户端套接字发送消息对象
CClientSocket * s = (CClientSocket *)m_plConn.GetNext(pos);
s->SendMsg(&msg);
}
pSocket->Init(this); // 新客户端套接字初始化
m_plConn.AddTail(pSocket); // 添加到已连接套接字列表中
UpdateData(TRUE);
m_strShow += "/r/n";
m_strShow += "一名游客进入聊天室";
UpdateData(FALSE); // 更新显示
}
else
{
delete pSocket;
}
}
void CServerDlg::OnButton1()
{
UpdateData(TRUE);
CMsg msg;
m_strShow += "/r/n";
m_strShow += m_strMsg;
UpdateData(FALSE); // 更新显示
m_Show.LineScroll(m_Show.GetLineCount());
msg.m_strMsg = m_strMsg;
for(POSITION pos=m_plConn.GetHeadPosition(); pos!=NULL;)
{ // 向客户端套接字发送消息对象
CClientSocket * s= (CClientSocket *)m_plConn.GetNext(pos);
s->SendMsg(&msg);
}
}