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()可看一下我的这篇,其中有一段相关解释。

  

转载于:https://www.cnblogs.com/darkchii/p/7891942.html

  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值