首页 > 代码库 > Windows程序设计笔记4:第10章:TCP/IP和网络通信

Windows程序设计笔记4:第10章:TCP/IP和网络通信

WinSock接口:Windows处理网络的API

套接字socket

流套接字:SOCKET_STREAM           可靠连接   TCP HTTP POP3

数据报套接字:SOCKET_DGRAM     不可靠连接 UDP

 

寻址方式:

1:sockaddr的第1个版本

struct sockaddr{

  u_short  sa_family;       //地址家族

  char      sa_data[14];   //数据

}

2.sockaddr的TCP/IP版本的 sockaddr_in

struct sockaddr_in{

  short       sin_family;       //地址家族

  u_short   sin_port;         //端口号

  struct  in_addr sin_addr; //IP地址

  char      sa_data[14];   //空字节,设为0,8个字节

}

WinSock编程流程

1:WinSock的装入、初始化、释放

  int WSAstartup{

    WORD  wVersionRequested;           //WinSock的版本

    LPWSADATA  lpWSAData;             //指针,返回DLL的详细信息

}

 int  WSAcleanup(void)

2:套接字的创建和关闭

SOCKET socket{

  int af;                             //套接字地址格式

  int type;                         //套接字类型

  int protocol;                //套接字使用协议

}

SOCKET_STREAM:TCP可靠的流套接字

SOCKET_DGRAM :UDP不可靠的数据报套接字

SOCKET_RAW     :原始套接字

 

3.绑定套接字

int bind(

  SOCKET s;                                      //套接字句柄

  const struct socketaddr*  name;     //关联的本地地址 

  int namelen;                                    //地址的长度

)

4.设置套接字进入监听状态

int listen(

  SOCKET s;            //套接字句柄

    int backlog;         //套接字尚未连接的最大数量

5.接受连接请求

SOCKET accept(

  SOCKET  s;

  struct socketaddr*  addr;    //指向地址

  int*  addlen;                        //指向地址长度的指针

)

 

6.收发数据

int send(

  SOCKET s;                             //套接字句柄

  const char FAR* buf;           //缓冲区地址

  int len,;                                //缓冲区长度

  int flags;                            //指定的调用方式,通常设为0;

int recv(SOCKET s,const char FAR*,int len,int)

 

技术分享

ServerDemo.cpp文件

#include <winsock2.h>	// 为了使用Winsock API函数
#include <stdio.h>
#include <windows.h>

// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")


int main(int argc, char* argv[])
{
	// 初始化WS2_32.dll
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 0);
	::WSAStartup(sockVersion, &wsaData);
	
	// 创建套节字
	SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(s == INVALID_SOCKET)
	{
		printf("Failed socket() \n");
		::WSACleanup();
		return 0;
	}
	
	// 填充sockaddr_in结构
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(8888);
	sin.sin_addr.S_un.S_addr = INADDR_ANY;
	
	// 绑定这个套节字到一个本地地址
	if(::bind(s, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		printf("Failed bind() \n");
		::WSACleanup();
		return 0;
	}
	
	// 进入监听模式
	if(::listen(s, 2) == SOCKET_ERROR)
	{
		printf("Failed listen()");
		::WSACleanup();
		return 0;
	}
	
	// 循环接受客户的连接请求
	sockaddr_in remoteAddr; 
	int nAddrLen = sizeof(remoteAddr);
	SOCKET client;
	char szText[] = " 10ServerDemo! \r\n";
	while(TRUE)
	{
		// 接受一个新连接
		client = ::accept(s, (SOCKADDR*)&remoteAddr, &nAddrLen);
		if(client == INVALID_SOCKET)
		{
			printf("Failed accept()");
			continue;
		}
		
		printf(" 接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));

		// 向客户端发送数据
		::send(client, szText, strlen(szText), 0);

		// 关闭同客户端的连接
		::closesocket(client);
	}
		
	// 关闭监听套节字
	::closesocket(s);
	// 释放WS2_32库
	::WSACleanup();	

	return 0;
}

ClientDemo.cpp文件  

#include <winsock2.h>	// 为了使用Winsock API函数
#include <stdio.h>
#include <windows.h>

// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")

int main(int argc, char* argv[])
{
	// 初始化WS2_32.dll
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 0);
	::WSAStartup(sockVersion, &wsaData);
	
	// 创建套节字
	SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(s == INVALID_SOCKET)
	{
		printf("Failed socket() \n");
		::WSACleanup();
		return 0;
	}

	// 也可以在这里调用bind函数绑定一个本地地址
	// 否则系统将会自动安排

	// 填写远程地址信息
	sockaddr_in servAddr; 
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(8888);
	// 注意,这里要填写服务器程序(10ServerDemo程序)所在机器的IP地址
	// 如果你的计算机没有联网,直接使用127.0.0.1即可
	servAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");

	if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)
	{
		printf("Failed connect() \n");
		::WSACleanup();
		return 0;
	}
	

	// 接收数据
	char buff[256];
	int nRecv = ::recv(s, buff, 256, 0);
	if(nRecv > 0)
	{
		buff[nRecv] = ‘\0‘;
		printf(" 接收到数据:%s", buff);
	}
	  
	// 关闭套节字
	::closesocket(s);
	// 释放WS2_32库
	::WSACleanup();	
	return 0;
}

TCPServer.h文件

 

#include <afxwin.h>		
#include <afxcmn.h>
#include <winsock2.h> 

// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")

#define MAX_SOCKET 56	// 定义此服务器所能接受的最大客户量

class CMyApp : public CWinApp
{
public:
	BOOL InitInstance();
};

class CMainDialog : public CDialog
{
public:
	CMainDialog(CWnd* pParentWnd = NULL);

protected:
	// 创建套节字,并设置为监听状态,准备接受客户的连接
	BOOL CreateAndListen(int nPort);
	// 关闭所有套节字,包括监听套节字和所有accept函数返回的套节字
	void CloseAllSocket();
	// 向客户连接列表中添加一个客户
	BOOL AddClient(SOCKET s);
	// 从客户连接列表中移处一个客户
	void RemoveClient(SOCKET s);

protected:
	// 两个子窗口控件,一个是状态栏,一个是列表框
	CStatusBarCtrl m_bar;
	CListBox m_listInfo;
	
	// 监听套节字句柄
	SOCKET m_socket;

	// 客户连接列表
	SOCKET m_arClient[MAX_SOCKET];	// 套节字数组
	int m_nClient;			// 上述数组的大小
	
protected:
	virtual BOOL OnInitDialog();
	virtual void OnCancel();
	// 开启或停止服务
	afx_msg void OnStart();
	// 清空信息
	afx_msg void OnClear();
	// 套节字通知事件
	afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
};

 

TCPServer.cpp文件  

 

#include "TCPClient.h"
#include "resource.h"


// 定义网络事件通知消息
#define WM_SOCKET WM_USER + 1	

CMyApp theApp;

BOOL CMyApp::InitInstance()
{
	// 初始化Winsock库
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 0);
	::WSAStartup(sockVersion, &wsaData);
	// 弹出主窗口对话框
	CMainDialog dlg;
	m_pMainWnd = &dlg;
	dlg.DoModal();
	// 释放Winsock库
	::WSACleanup();
	return FALSE;
}

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG, pParentWnd)
{
}


BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
ON_BN_CLICKED(IDC_START, OnStart)
ON_BN_CLICKED(IDC_CLEAR, OnClear)
ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

BOOL CMainDialog::OnInitDialog()
{
	CDialog::OnInitDialog();
	// 设置图标
	SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);
	// 创建状态栏,设置它的属性
	m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, 101);
	m_bar.SetBkColor(RGB(0xa6, 0xca, 0xf0));		// 背景色
	int arWidth[] = { 200, -1 };
	m_bar.SetParts(2, arWidth);				// 分栏
	m_bar.SetText(" Windows程序设计进阶之路!", 1, 0);	// 第一个栏的文本
	m_bar.SetText(" 空闲", 0, 0);				// 第二个栏的文本
	// 设置列表框控件到m_listInfo对象的关联
	m_listInfo.SubclassDlgItem(IDC_INFO, this);
	
	// 初始化监听套节字和连接列表
	m_socket = INVALID_SOCKET;
	m_nClient = 0;
	
	// 下面是取得本地IP地址的过程,将它显示在状态栏的第一个分栏中
	// 取得本机名称	
	char szHost[256];
	::gethostname(szHost, 256);
	// 通过本机名称取得地址信息
	HOSTENT* pHost = gethostbyname(szHost);
	if(pHost != NULL)
	{  	
		CString sIP;
		
		// 得到第一个IP地址
		in_addr *addr =(in_addr*) *(pHost->h_addr_list);
		
		// 显示给用户
		sIP.Format(" 本机IP:%s", inet_ntoa(addr[0]));
		m_bar.SetText(sIP, 0, 0);
	}
	
	return TRUE;
}

void CMainDialog::OnStart()
{
	if(m_socket == INVALID_SOCKET)  // 开启服务
	{
		// 取得端口号
		CString sPort;
		GetDlgItem(IDC_PORT)->GetWindowText(sPort);
		int nPort = atoi(sPort);
		if(nPort < 1 || nPort > 65535)
		{
			MessageBox("端口号错误!");
			return;
		}

		// 创建监听套节字,使它进入监听状态
		if(!CreateAndListen(nPort))
		{
			MessageBox("启动服务出错!");
			return;
		}
		
		// 设置相关子窗口控件状态
		GetDlgItem(IDC_START)->SetWindowText("停止服务");
		m_bar.SetText(" 正在监听……", 0, 0);
		GetDlgItem(IDC_PORT)->EnableWindow(FALSE);
	}
	else				// 停止服务
	{
		// 关闭所有连接
		CloseAllSocket();

		// 设置相关子窗口控件状态
		GetDlgItem(IDC_START)->SetWindowText("开启服务");
		m_bar.SetText(" 空闲", 0, 0);
		GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
	}
}

void CMainDialog::OnCancel()
{
	CloseAllSocket();
	CDialog::OnCancel();
}

void CMainDialog::OnClear()
{
	m_listInfo.ResetContent();
}

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)
{
	// 取得有事件发生的套节字句柄
	SOCKET s = wParam;
	// 查看是否出错
	if(WSAGETSELECTERROR(lParam))
	{
		RemoveClient(s);
		::closesocket(s);
		return 0;
	}
	// 处理发生的事件
	switch(WSAGETSELECTEVENT(lParam))
	{
	case FD_ACCEPT:		// 监听中的套接字检测到有连接进入
		{
			if(m_nClient < MAX_SOCKET)
			{
				// 接受连接请求,新的套节字client是新连接的套节字
				SOCKET client = ::accept(s, NULL, NULL);
				// 设置新的套节字为窗口通知消息类型
				int i = ::WSAAsyncSelect(client, 
					m_hWnd, WM_SOCKET, FD_READ|FD_WRITE|FD_CLOSE);
				AddClient(client);
			}
			else
			{
				MessageBox("连接客户太多!");
			}
		}
		break;

	case FD_CLOSE:		// 检测到套接字对应的连接被关闭。
		{
			RemoveClient(s);
			::closesocket(s);
		}
		break;

	case FD_READ:		// 套接字接受到对方发送过来的数据包
		{

				// 取得对方的IP地址和端口号(使用getpeername函数)
			// Peer对方的地址信息
			sockaddr_in sockAddr;
			memset(&sockAddr, 0, sizeof(sockAddr));
			int nSockAddrLen = sizeof(sockAddr);
			::getpeername(s, (SOCKADDR*)&sockAddr, &nSockAddrLen);
			// 转化为主机字节顺序
			int nPeerPort = ::ntohs(sockAddr.sin_port);
			// 转化为字符串IP
			CString sPeerIP = ::inet_ntoa(sockAddr.sin_addr);
			
				// 取得对方的主机名称
			// 取得网络字节顺序的IP值
			DWORD dwIP = ::inet_addr(sPeerIP);
			// 获取主机名称,注意其中第一个参数的转化
			hostent* pHost = ::gethostbyaddr((LPSTR)&dwIP, 4, AF_INET);
			char szHostName[256];
			strncpy(szHostName, pHost->h_name, 256);		 

			// 接受真正的网络数据
			char szText[1024] = { 0 };
			::recv(s, szText, 1024, 0);

			// 显示给用户
			CString strItem = CString(szHostName) + "["+ sPeerIP+ "]: " + CString(szText);
			m_listInfo.InsertString(0, strItem);

		}
		break;
	}
	return 0;
}


BOOL CMainDialog::CreateAndListen(int nPort)
{
	if(m_socket == INVALID_SOCKET)
		::closesocket(m_socket);

	// 创建套节字
	m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(m_socket == INVALID_SOCKET)
		return FALSE;
	
	// 填写要关联的本地地址
	sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(nPort);
	sin.sin_addr.s_addr = INADDR_ANY;
	// 绑定端口
	if(::bind(m_socket, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR)
	{
		return FALSE;
	}

	// 设置socket为窗口通知消息类型
	::WSAAsyncSelect(m_socket, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CLOSE);
	// 进入监听模式
	::listen(m_socket, 5);

	return TRUE;
}


BOOL CMainDialog::AddClient(SOCKET s)
{
	if(m_nClient < MAX_SOCKET)
	{
		// 添加新的成员
		m_arClient[m_nClient++] = s;
		return TRUE;
	}
	return FALSE;
}

void CMainDialog::RemoveClient(SOCKET s)
{
	BOOL bFind = FALSE;
	for(int i=0; i<m_nClient; i++)
	{
		if(m_arClient[i] == s)
		{
			bFind = TRUE;
			break;
		}
	}

	// 如果找到就将此成员从列表中移除
	if(bFind)
	{
		m_nClient--;
		// 将此成员后面的成员都向前移动一个单位
		for(int j=i; j<m_nClient; j++)
		{
			m_arClient[j] = m_arClient[j+1];
		}
	}
}

void CMainDialog::CloseAllSocket()
{
	// 关闭监听套节字
	if(m_socket != INVALID_SOCKET)
	{
		::closesocket(m_socket);
		m_socket = INVALID_SOCKET;
	}
	
	// 关闭所有客户的连接
	for(int i=0; i<m_nClient; i++)
	{
		::closesocket(m_arClient[i]);
	}
	m_nClient = 0;
}

 

 TCPClient.h文件

 

#include <afxwin.h>	
#include <afxcmn.h>
#include <winsock2.h> 

// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")

class CMyApp : public CWinApp
{
public:
	BOOL InitInstance();
};

class CMainDialog : public CDialog
{
public:
	CMainDialog(CWnd* pParentWnd = NULL);

protected:
	// 连接服务器
	BOOL Connect(LPCTSTR pszRemoteAddr, u_short nPort);
	// 向文本框中添加文本
	void AddStringToList(LPCTSTR pszText, BOOL bRecv = TRUE);

protected:
	// 状态栏子窗口控件
	CStatusBarCtrl m_bar;	
	// 用于与服务器取得连接的套节字句柄
	SOCKET m_socket;

protected:
	virtual BOOL OnInitDialog();
	virtual void OnCancel();
	// 取得或断开连接
	afx_msg void OnButtonConnect();
	// 发送数据
	afx_msg void OnButtonSend();
	// 清空编辑框
	afx_msg void OnButtonClear();
	// 套节字通知事件
	afx_msg long OnSocket(WPARAM wParam, LPARAM lParam);
	DECLARE_MESSAGE_MAP()
};

 

TCPClient.cpp文件

#include "TCPClient.h"
#include "resource.h"

// 定义网络事件通知消息
#define WM_SOCKET WM_USER + 1	

CMyApp theApp;

BOOL CMyApp::InitInstance()
{
	// 初始化Winsock库
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 0);
	::WSAStartup(sockVersion, &wsaData);
	// 弹出主窗口对话框
	CMainDialog dlg;
	m_pMainWnd = &dlg;
	dlg.DoModal();
	// 释放Winsock库
	::WSACleanup();
	return FALSE;
}

CMainDialog::CMainDialog(CWnd* pParentWnd):CDialog(IDD_MAINDIALOG, pParentWnd)
{
}

BEGIN_MESSAGE_MAP(CMainDialog, CDialog)
ON_BN_CLICKED(IDC_CONNECT, OnButtonConnect)
ON_BN_CLICKED(IDC_SEND, OnButtonSend)
ON_BN_CLICKED(IDC_CLEAR, OnButtonClear)
ON_MESSAGE(WM_SOCKET, OnSocket)
END_MESSAGE_MAP()

BOOL CMainDialog::OnInitDialog()
{
	CDialog::OnInitDialog();
	// 设置图标
	SetIcon(theApp.LoadIcon(IDI_MAIN), FALSE);
	// 创建状态栏,设置它的属性
	m_bar.Create(WS_CHILD|WS_VISIBLE|SBS_SIZEGRIP, CRect(0, 0, 0, 0), this, 101);
	m_bar.SetBkColor(RGB(0xa6, 0xca, 0xf0));		// 背景色
	int arWidth[] = { 200, -1 };
	m_bar.SetParts(2, arWidth);				// 分栏
	m_bar.SetText(" Windows程序设计进阶之路!", 1, 0);	// 第一个栏的文本
	m_bar.SetText(" 空闲", 0, 0);				// 第二个栏的文本
	// 初始化发送按钮和发送编辑框的状态
	GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
	GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);

	// 初始化连接套节字
	m_socket = INVALID_SOCKET;

	return TRUE;
}

void CMainDialog::OnCancel()
{
	if(m_socket != INVALID_SOCKET)
		::closesocket(m_socket);

	CDialog::OnCancel();
}

void CMainDialog::OnButtonClear()
{
	GetDlgItem(IDC_INFO)->SetWindowText("");	
}

void CMainDialog::OnButtonConnect()
{
	if(m_socket == INVALID_SOCKET)  // 连接服务器
	{
		// 取得服务器地址
		CString sAddr;
		GetDlgItem(IDC_ADDR)->GetWindowText(sAddr);
		if(sAddr.IsEmpty())
		{
			MessageBox("请输入服务器地址!");
			return;
		}

		// 取得端口号
		CString sPort;
		GetDlgItem(IDC_PORT)->GetWindowText(sPort);
		int nPort = atoi(sPort);
		if(nPort < 1 || nPort > 65535)
		{
			MessageBox("端口号错误!");
			return;
		}

		// 试图连接服务器
		if(!Connect(sAddr, nPort))
		{
			MessageBox("连接服务器出错!");
			return;
		}
		
		// 设置用户界面
		GetDlgItem(IDC_CONNECT)->SetWindowText("取消");
		m_bar.SetText(" 正在连接……", 0, 0);
	}
	else				// 断开服务器
	{
		// 关闭套节字
		::closesocket(m_socket);
		m_socket = INVALID_SOCKET;

		// 设置用户界面
		GetDlgItem(IDC_CONNECT)->SetWindowText("连接服务器");
		m_bar.SetText(" 空闲", 0, 0);	
		GetDlgItem(IDC_ADDR)->EnableWindow(TRUE);
		GetDlgItem(IDC_PORT)->EnableWindow(TRUE);
		GetDlgItem(IDC_TEXT)->EnableWindow(FALSE);
		GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
	}
}

long CMainDialog::OnSocket(WPARAM wParam, LPARAM lParam)
{
	// 取得有事件发生的套节字句柄
	SOCKET s = wParam;
	// 查看是否出错
	if(WSAGETSELECTERROR(lParam))
	{
		if(m_socket != SOCKET_ERROR)
			OnButtonConnect();
		m_bar.SetText(" 连接出错!", 0, 0);
		return 0;
	}
	// 处理发生的事件
	switch(WSAGETSELECTEVENT(lParam))
	{	
	case FD_CONNECT:	// 套节字正确的连接到服务器
		{
			// 设置用户界面
			GetDlgItem(IDC_CONNECT)->SetWindowText("断开连接");

			GetDlgItem(IDC_ADDR)->EnableWindow(FALSE);
			GetDlgItem(IDC_PORT)->EnableWindow(FALSE);
			GetDlgItem(IDC_TEXT)->EnableWindow(TRUE);
			GetDlgItem(IDC_SEND)->EnableWindow(TRUE);
			m_bar.SetText(" 已经连接到服务器", 0, 0);
		}
		break;

	case FD_READ:		// 套接字接受到对方发送过来的数据包
		{
			// 从服务器接受数据
			char szText[1024] = { 0 };
			::recv(s, szText, 1024, 0);
			// 显示给用户
			AddStringToList(CString(szText) + "\r\n");
		}
		break;

	case FD_CLOSE:
		OnButtonConnect();
		break;
	}

	return 0;
}

void CMainDialog::OnButtonSend()
{
	if(m_socket == INVALID_SOCKET)
	{
		return;
	}

	// 取得要发送的字符串
	CString sText;
	GetDlgItem(IDC_TEXT)->GetWindowText(sText);

	// 添加一个“回车换行”
	// 注意,添加它并不是必须的,但是如果使用本软件作为客户端调试网络协议,
	// 比如SMTP、FTP等,就要添加它了。因为这些协议都要求使用“回车换行”作为一个命令的结束标记
	sText += "\r\n";

	// 发送数据到服务器
	if(::send(m_socket, sText, sText.GetLength(), 0) != -1)
	{
		AddStringToList(sText, FALSE);
		GetDlgItem(IDC_TEXT)->SetWindowText("");
	}
}

BOOL CMainDialog::Connect(LPCTSTR pszRemoteAddr, u_short nPort)
{
	// 创建套节字
	m_socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if(m_socket == INVALID_SOCKET)
	{
		return FALSE;
	}
	
	// 设置socket为窗口通知消息类型
	::WSAAsyncSelect(m_socket, m_hWnd,
		WM_SOCKET, FD_CONNECT | FD_CLOSE | FD_WRITE | FD_READ);
	
	// 假定szAddr是IP地址
	ULONG uAddr = ::inet_addr(pszRemoteAddr);
        if(uAddr == INADDR_NONE)
	{
                // 不是IP地址,就认为这是主机名称
		// 从主机名取得IP地址
		hostent* pHost = ::gethostbyname(pszRemoteAddr);
		if(pHost == NULL)
		{
			::closesocket(m_socket);
			m_socket = INVALID_SOCKET;
			return FALSE;
		}
		// 得到以网络字节顺序排列的IP地址
                uAddr = ((struct in_addr*)*(pHost->h_addr_list))->s_addr;
        }
	
        // 填写服务器地址信息
	sockaddr_in remote;
        remote.sin_addr.S_un.S_addr = uAddr;
        remote.sin_family = AF_INET;
        remote.sin_port = htons(nPort);
	
        // 连接到远程机
        ::connect(m_socket, (sockaddr*)&remote, sizeof(sockaddr));
	
	return TRUE;
}

void CMainDialog::AddStringToList(LPCTSTR pszText, BOOL bRecv)
{
	CString strEdit;
	GetDlgItem(IDC_INFO)->GetWindowText(strEdit);

	if(bRecv)
	{
		strEdit += "【Recv】:";
		strEdit += pszText;
	}
	else
	{
		strEdit += "【Send】:";
		strEdit += pszText;
	}
	GetDlgItem(IDC_INFO)->SetWindowText(strEdit);	
}

 

Windows程序设计笔记4:第10章:TCP/IP和网络通信