windows網絡編程-C語言實現簡單的TCP協議聊天


  TCP/IP協議(面向連接協議)類似於打電話時,對方一定在手機附近並且此刻都在和對方進行通話。一定保證雙方都在線,才能進行數據傳輸。UDP/IP協議(無連接協議)就像郵箱,不保證對方一定在等你郵件且對方不在你也可以給對方發送數據。實際上TCP協議、UDP協議,還有重要的TCP協議中的三次握手(建立連接)和四次揮手(關閉連接)等在網上也都解釋得非常詳細了,所以我就不多說了。

  Server端程序代碼:

/*
 *	服務器端 Server.c
 *    
 */
#include <winsock2.h>
#include <stdio.h>
#include <string.h>

#define BUFFSIZE 1024

int main(int argc, char**argv)
{
    int				Ret;
    WSADATA			wsaData;
    SOCKET			ListeningSocket;
    SOCKET			NewConnection;
    SOCKADDR_IN		ServerAddr;
    SOCKADDR_IN		ClientAddr;
    int				ClientAddrLen = sizeof(ClientAddr);
    unsigned short	Port = 5150;
    char			sendData[BUFFSIZE];
    char			recvData[BUFFSIZE];

    if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
    {
        printf("WSASTARTUP_ERROR: %d\n", Ret);
        return 0;
    }

    //創建一個套接字來監聽客戶機連接
    if((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    {
        printf("SOCKET_ERROR: %d\n", INVALID_SOCKET);
        return 0;
    }


    /*
     * 填充SOCKADDR_IN結構,這個結構將告知bind我們想要在5150端口監聽所有接口上的連接
     */
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(Port); //將端口變量從主機字節順序轉換位網絡字節順序
    ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);


    //使用bind將這個地址信息和套接字綁定起來
    if(bind(ListeningSocket, (SOCKADDR *)&ServerAddr, sizeof(ServerAddr)) == SOCKET_ERROR)
    {
        printf("BIND_ERROR: %d\n", SOCKET_ERROR);
        return 0;
    }

    //監聽客戶機連接。這里使用5個backlog
    if(listen(ListeningSocket, 5) == SOCKET_ERROR)
    {
        printf("LISTEN_ERROR: %d\n", SOCKET_ERROR);
        return 0;
    }

	//連接到達時,接受連接
	printf("正在接受連接...");
    if((NewConnection = accept(ListeningSocket, (SOCKADDR *)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET)
    {
        printf("ACCPET_ERROR: %d\n", INVALID_SOCKET);
        closesocket(ListeningSocket);
        return 0;
    }
    printf("檢測到一個連接: %s 端口:%d\n", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));

    //聊天
    while(true)
    {
        //接收數據
        Ret = recv(NewConnection, recvData, BUFFSIZE, 0);
        if(Ret > 0)
            printf("C.C.: %s\n", recvData);
        else if(Ret < 0)
            printf("RECV_ERROR: %d\n",  SOCKET_ERROR);
        else
        {
            printf("對方退出程序,聊天結束!");
            break;
        }

		//發送數據
        printf("\n魯魯:");
        scanf("%s", sendData);
		if(strcmp(sendData, "quit") == 0)	//退出
			break;
        if(send(NewConnection, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
        {
            printf("消息發送失敗!\n");
            break;
        }
    }
	//從容關閉
	shutdown(NewConnection, SD_BOTH);

    //完成新接受的連接后,用closesocket API關閉這些套接字
    closesocket(NewConnection);
    closesocket(ListeningSocket);

    //應用程序完成對接的處理后,調用WSACleanup
    if(WSACleanup() == SOCKET_ERROR)
    {
        printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
        return 0;
    }

	system("pause");
    return 0;
}

  Client端程序代碼:

/*
 *	客戶端 Client.c
 *
 */
#include <winsock2.h>
#include <stdio.h>
#include <string.h>

#define BUFFSIZE 1024

int main(int argc, char**argv)
{
	int				Ret;
	WSADATA			wsaData;
	SOCKET			s;
	SOCKADDR_IN		ServerAddr;
	unsigned short	Port = 5150;
	char			sendData[BUFFSIZE];
	char			recvData[BUFFSIZE];

	if((Ret = WSAStartup(MAKEWORD(2,2), &wsaData)) != 0)
	{
		printf("WSASTARTUP_ERROR: %d\n", Ret);
		return 0;
	}

	if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		printf("SOCKET_ERROR: %d\n", INVALID_SOCKET);
		return 0;
	}

	ServerAddr.sin_family = AF_INET;
	ServerAddr.sin_port = htons(Port);
	ServerAddr.sin_addr.S_un.S_addr = inet_addr("192.168.1.101");// 這里S_un.S_addr在不同的IDE中可能不一樣,然后IPv4地址使用該程序所運行在的PC上的IPv4地址

	if((connect(s, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) == SOCKET_ERROR)
	{
		printf("CONNECT_ERROR: %d\n", SOCKET_ERROR);
		closesocket(s);
		return 0;
	}

	//Chat
	while(true)
	{
		printf("\nC.C:");
		scanf("%s", sendData);
		if(strcmp(sendData, "quit") == 0)	//quit
			break;
		if(send(s, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
		{
			printf("消息發送失敗!\n");
			break;
		}

		Ret = recv(s, recvData, BUFFSIZE, 0);
		if(Ret > 0)
			printf("魯魯: %s\n", recvData);
		else if(Ret < 0)
			printf("RECV_ERROR: %d\n", SOCKET_ERROR);
		else
		{
			printf("對方退出程序,聊天結束!");
			break;
		}
	}
	shutdown(s, SD_BOTH);
	closesocket(s);

	if(WSACleanup() == SOCKET_ERROR)
	{
		printf("WSACLEANUP_ERROR: %d\n", WSAGetLastError());
		return 0;
	}

	system("pause");
	return 0;
}

  運行結果:

  對於所有可能出現的錯誤我都加上了會出錯的函數名前綴,以便於定位出現錯誤的位置。

  其他的書上解釋得很詳細,就不暴露自己水平了233...

 

p.s.2018-05-13 15:10:46

  AF_INET的原型是:

#define AF_INET 2

  然后關於客戶端代碼中的inet_addr()可看一下我的這篇,其中有一段相關解釋。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM