Demystifying TCP/IP, UDP, and Socket Programming with a Practical MFC Example

This article explains the fundamentals of TCP/IP and UDP protocols, clarifies where sockets fit in the network stack, describes their role as a façade layer, and provides a complete MFC‑based client‑server example with full source code for initializing, binding, listening, connecting, sending, and receiving data.

21CTO
21CTO
21CTO
Demystifying TCP/IP, UDP, and Socket Programming with a Practical MFC Example

What are TCP/IP and UDP?

TCP/IP (Transmission Control Protocol/Internet Protocol) is an industrial‑standard protocol suite designed for wide‑area networks. UDP (User Datagram Protocol) is a counterpart protocol within the TCP/IP family, providing connection‑less data transmission.

The TCP/IP suite includes transport, network, and link layers, illustrating the relationship between TCP and UDP.

Where does the socket fit?

The socket is not shown in the protocol diagram; it resides as an abstraction layer between the application layer and the TCP/IP suite, providing a simple interface that hides the underlying complexity.

What is a socket?

A socket is an intermediate software abstraction that offers a set of interfaces for communication with the TCP/IP protocol suite. In design patterns it acts as a façade, exposing simple functions while the protocol details remain hidden.

Analogy: making a phone call – dialing establishes a connection, conversation proceeds, and hanging up ends it, similar to how TCP establishes a connection.

Server implementation (MFC example)

The server initializes a socket, binds it to a port, listens for connections, accepts a client, receives data, processes it, and sends a response.

int Receive(SOCKET fd, char *szText, int len)
{
    int cnt = len;
    int rc;
    while (cnt > 0)
    {
        rc = recv(fd, szText, cnt, 0);
        if (rc == SOCKET_ERROR) return -1;
        if (rc == 0) return len - cnt;
        szText += rc;
        cnt -= rc;
    }
    return len;
}
int Send(SOCKET fd, char *szText, int len)
{
    int cnt = len;
    int rc;
    while (cnt > 0)
    {
        rc = send(fd, szText, cnt, 0);
        if (rc == SOCKET_ERROR) return -1;
        if (rc == 0) return len - cnt;
        szText += rc;
        cnt -= rc;
    }
    return len;
}

Server start routine:

#define DEFAULT_PORT 2000
void CServerDlg::OnStart()
{
    sockaddr_in local;
    DWORD dwThreadID = 0;
    local.sin_family = AF_INET;
    local.sin_port = htons(DEFAULT_PORT);
    local.sin_addr.S_un.S_addr = INADDR_ANY;
    m_Listening = socket(AF_INET, SOCK_STREAM, 0);
    if (m_Listening == INVALID_SOCKET) return;
    if (bind(m_Listening, (LPSOCKADDR)&local, sizeof(local)) == SOCKET_ERROR)
    {
        closesocket(m_Listening);
        return;
    }
    m_hListenThread = ::CreateThread(NULL, 0, ListenThread, this, 0, &dwThreadID);
    m_StartBtn.EnableWindow(FALSE);
    m_StopBtn.EnableWindow(TRUE);
}

Listen thread function:

DWORD WINAPI CServerDlg::ListenThread(LPVOID lpparam)
{
    CServerDlg* pDlg = (CServerDlg*)lpparam;
    if (pDlg == NULL) return 0;
    SOCKET Listening = pDlg->m_Listening;
    if (listen(Listening, 40) == SOCKET_ERROR) return 0;
    char szBuf[MAX_PATH];
    memset(szBuf, 0, MAX_PATH);
    while (1)
    {
        SOCKET ConnectSocket;
        sockaddr_in ClientAddr;
        int nLen = sizeof(sockaddr);
        ConnectSocket = accept(Listening, (sockaddr*)&ClientAddr, &nLen);
        char *pAddrname = inet_ntoa(ClientAddr.sin_addr);
        pDlg->Receive(ConnectSocket, szBuf, 100);
        pDlg->SetRequestText(szBuf);
        strcat(szBuf, " :我是老猫,收到(");
        strcat(szBuf, pAddrname);
        strcat(szBuf, ")");
        pDlg->Send(ConnectSocket, szBuf, 100);
    }
    return 0;
}

Client implementation

The client creates a socket, connects to the server, sends a request, receives the reply, and closes the socket.

#define DEFAULT_PORT 2000
void CClientDlg::OnSend()
{
    DWORD dwIP = 0;
    TCHAR szText[MAX_PATH];
    memset(szText, 0, MAX_PATH);
    m_IP.GetWindowText(szText, MAX_PATH);
    dwIP = inet_addr(szText);
    m_RequestEdit.GetWindowText(szText, MAX_PATH);
    sockaddr_in local;
    SOCKET socketTmp;
    local.sin_family = AF_INET;
    local.sin_port = htons(DEFAULT_PORT);
    local.sin_addr.S_un.S_addr = dwIP;
    socketTmp = socket(AF_INET, SOCK_STREAM, 0);
    if (connect(socketTmp, (LPSOCKADDR)&local, sizeof(local)) < 0)
    {
        closesocket(socketTmp);
        MessageBox("连接服务器失败。");
        return;
    }
    Send(socketTmp, szText, 100);
    memset(szText, 0, MAX_PATH);
    Receive(socketTmp, szText, 100);
    TCHAR szMessage[MAX_PATH];
    memset(szMessage, 0, MAX_PATH);
    strcat(szMessage, szText);
    m_ReplyBtn.SetWindowText(szMessage);
    closesocket(socketTmp);
}

Using the loopback address 127.0.0.1 lets the server and client run on the same machine for easy debugging; replace it with a remote IP to communicate across a network.

With both theory and a working example, socket programming is no longer mysterious.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

TCP/IPsocket programmingC++UDPclient-serverMFC
21CTO
Written by

21CTO

21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.