winsock流程

来源:互联网 发布:java拦截器执行流程 编辑:程序博客网 时间:2024/05/05 18:23

相应的函数说明

函数定义: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);
    }   
}

 

 

原创粉丝点击