zoukankan      html  css  js  c++  java
  • 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
    ", Ret);
            return 0;
        }
    
        //创建一个套接字来监听客户机连接
        if((ListeningSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
        {
            printf("SOCKET_ERROR: %d
    ", 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
    ", SOCKET_ERROR);
            return 0;
        }
    
        //监听客户机连接。这里使用5个backlog
        if(listen(ListeningSocket, 5) == SOCKET_ERROR)
        {
            printf("LISTEN_ERROR: %d
    ", SOCKET_ERROR);
            return 0;
        }
    
    	//连接到达时,接受连接
    	printf("正在接受连接...");
        if((NewConnection = accept(ListeningSocket, (SOCKADDR *)&ClientAddr, &ClientAddrLen)) == INVALID_SOCKET)
        {
            printf("ACCPET_ERROR: %d
    ", INVALID_SOCKET);
            closesocket(ListeningSocket);
            return 0;
        }
        printf("检测到一个连接: %s 端口:%d
    ", inet_ntoa(ClientAddr.sin_addr), ntohs(ClientAddr.sin_port));
    
        //聊天
        while(true)
        {
            //接收数据
            Ret = recv(NewConnection, recvData, BUFFSIZE, 0);
            if(Ret > 0)
                printf("C.C.: %s
    ", recvData);
            else if(Ret < 0)
                printf("RECV_ERROR: %d
    ",  SOCKET_ERROR);
            else
            {
                printf("对方退出程序,聊天结束!");
                break;
            }
    
    		//发送数据
            printf("
    鲁鲁:");
            scanf("%s", sendData);
    		if(strcmp(sendData, "quit") == 0)	//退出
    			break;
            if(send(NewConnection, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
            {
                printf("消息发送失败!
    ");
                break;
            }
        }
    	//从容关闭
    	shutdown(NewConnection, SD_BOTH);
    
        //完成新接受的连接后,用closesocket API关闭这些套接字
        closesocket(NewConnection);
        closesocket(ListeningSocket);
    
        //应用程序完成对接的处理后,调用WSACleanup
        if(WSACleanup() == SOCKET_ERROR)
        {
            printf("WSACLEANUP_ERROR: %d
    ", 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
    ", Ret);
    		return 0;
    	}
    
    	if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
    	{
    		printf("SOCKET_ERROR: %d
    ", 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
    ", SOCKET_ERROR);
    		closesocket(s);
    		return 0;
    	}
    
    	//Chat
    	while(true)
    	{
    		printf("
    C.C:");
    		scanf("%s", sendData);
    		if(strcmp(sendData, "quit") == 0)	//quit
    			break;
    		if(send(s, sendData, BUFFSIZE, 0) == SOCKET_ERROR)
    		{
    			printf("消息发送失败!
    ");
    			break;
    		}
    
    		Ret = recv(s, recvData, BUFFSIZE, 0);
    		if(Ret > 0)
    			printf("鲁鲁: %s
    ", recvData);
    		else if(Ret < 0)
    			printf("RECV_ERROR: %d
    ", SOCKET_ERROR);
    		else
    		{
    			printf("对方退出程序,聊天结束!");
    			break;
    		}
    	}
    	shutdown(s, SD_BOTH);
    	closesocket(s);
    
    	if(WSACleanup() == SOCKET_ERROR)
    	{
    		printf("WSACLEANUP_ERROR: %d
    ", WSAGetLastError());
    		return 0;
    	}
    
    	system("pause");
    	return 0;
    }

      运行结果:

      对于所有可能出现的错误我都加上了会出错的函数名前缀,以便于定位出现错误的位置。

      其他的书上解释得很详细,就不暴露自己水平了233...

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

      AF_INET的原型是:

    #define AF_INET 2
    

      然后关于客户端代码中的inet_addr()可看一下我的这篇,其中有一段相关解释。

      

  • 相关阅读:
    List、Set、Map集合大杂烩
    Android的DatePicker和TimePicker-android学习之旅(三十八)
    Ubuntu 启动项、菜单 改动 防止隐藏
    Ehcache 整合Spring 使用页面、对象缓存
    Spring MVC 相关资料整理
    Spring + Spring MVC+Hibernate框架整合详细配置
    @RequestMapping 用法详解之地址映射
    关于时间统计问题
    Oracle之物化视图
    Oracle:高效插入大量数据经验之谈
  • 原文地址:https://www.cnblogs.com/darkchii/p/7891942.html
Copyright © 2011-2022 走看看