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