写了一个聊天室,可以支持多人在线,但是现在的问题是发送信息存在无法覆盖的问题
第一个是服务端的代码,第二个是客户端的代码
cpp
//聊天室
//服务端流程
//1 创建socket套接字:网络接口
//2 绑定IP和端口号;IP是电脑的地址,端口号是APP的地址
//3 监听:只是用来接收连接的
//4 接收客户端连接
//5 接收客户端消息
//6 发送消息给客户端
//7 关闭套接字
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
//客户端线程函数
DWORD WINAPI client_thread(LPVOID lpParameter);
int main ()
{
//在windos上开启网络权限
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
//非常固定,只有windos需要
//创建套接字
/*
SOCKET socket(int af, int type, int protocol);
af: 地址族,AF_INET表示IPv4 // AF_INET6表示IPv6
type: 套接字类型,SOCK_STREAM表示TCP//一个是流式协议,一个是数据包
protocol: 协议,0表示使用默认协议
*/
SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);
//判读是否创建成功
if (listen_socket == INVALID_SOCKET)
{
printf("socket failed: %d,no creat\n", WSAGetLastError());
return 1;
}
//绑定IP和端口号
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(8080);
//这里涉及到大小端问题,htons(8080)表示将8080转换为网络字节序
//server_addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);//可以理解为一个选项 网卡 127.0.0.1(本地回环) 只接受那个网卡的数据
long ip = inet_addr("0.0.0.0");
server_addr.sin_addr.S_un.S_addr = ip;
//sockaddr_in的成员是
//unsigned short sin_family;
//unsigned short sin_port;
//struct in_addr sin_addr;
//sin_family: 地址族,AF_INET表示IPv4
//sin_port: 端口号,htons(8080)表示将8080转换为网络字节序
//sin_addr.S_un.S_addr: IP地址,INADDR_ANY表示任何IP地址
/*
int bind(SOCKET s, const struct sockaddr *addr, int addrlen);
s: 套接字
addr: 地址结构体
addrlen: 地址结构体长度
*/
//sockaddr也是一个结构体,但是它是通用的,可以用于任何协议实际上和sockaddr_in是一样的
int ret = bind(listen_socket, (struct sockaddr *)&server_addr, sizeof(server_addr));
//判断是否绑定成功
if (ret == SOCKET_ERROR)
{
printf("bind failed: %d,no bind\n", WSAGetLastError());
return 1;
}
//3.开启监听属性
//需要用到listen函数
//listen函数的参数是
//套接字和最大连接数
//最大连接数是指服务器可以同时处理的最大连接数
//如果服务器的连接数超过了最大连接数,那么新的连接将被拒绝
//判断是否开启成功
if (listen(listen_socket, 10) == SOCKET_ERROR)
{
printf("listen failed: %d\n", WSAGetLastError());
closesocket(listen_socket);
WSACleanup();
return 1;
}
//等待客户端连接
//accept函数用于接受客户端连接
//accept函数的参数是
//套接字
//客户端地址结构体
//地址结构体长度
//这是一个阻塞函数,等到客户端连接后才返回,如果没有客户端连接,则一直等待
SOCKET client_socket;
struct sockaddr_in client_addr;
int client_addr_len = sizeof(client_addr);
while(1)
{
client_socket = accept(listen_socket, (struct sockaddr *)&client_addr, &client_addr_len);
//返回的SOCKET是客户端的套接字,才是和客户端通信的套接字
//判断是否连接成功
if (client_socket == INVALID_SOCKET)
{
printf("accept failed: %d\n", WSAGetLastError());
continue;
}
SOCKET *sockfd = (SOCKET *)malloc(sizeof(SOCKET));
*sockfd = client_socket;
//创建线程处理客户端连接
HANDLE hThread = CreateThread(NULL, 0, client_thread, sockfd, 0, NULL);
if (hThread == NULL)
{
printf("CreateThread failed\n");
free(sockfd);
closesocket(client_socket);
}
else
{
CloseHandle(hThread);
}
printf("Client connected!\n");
}
closesocket(listen_socket);
WSACleanup();
return 0;
}
DWORD WINAPI client_thread(LPVOID lpParameter)
{
SOCKET *sockfd = (SOCKET *)lpParameter;
SOCKET client_socket = *sockfd;
free(sockfd);
char buf[1024] = {0};
while(1)
{
int recv_ret = recv(client_socket, buf, sizeof(buf), 0);
if (recv_ret == SOCKET_ERROR)
{
printf("recv failed: %d\n", WSAGetLastError());
break;
}
else if (recv_ret == 0)
{
printf("Client disconnected\n");
break;
}
printf("recv: %s\n", buf);
send(client_socket, buf, recv_ret, 0);
}
closesocket(client_socket);
return 0;
}
cpp
//聊天室的客户端
//创建socket套接字
//连接服务器
//发送消息
//接收消息
//关闭套接字(连接)
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")
int main()
{
// 初始化Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Failed to initialize Winsock\n");
return 1;
}
// 创建套接字
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET) {
printf("Failed to create socket\n");
WSACleanup();
return 1;
}
//连接服务器
struct sockaddr_in target;
target.sin_family = AF_INET;
target.sin_port = htons(8080);
target.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sock, (struct sockaddr*)&target, sizeof(target)) == SOCKET_ERROR) {
printf("Failed to connect to server\n");
closesocket(sock);
WSACleanup();
return 1;
}
while(1)
{
//发送信息
char buffer[1024];
printf("请输入要发送的信息:");
scanf("%s", buffer);
send(sock, buffer, strlen(buffer), 0);
// 接收服务器响应
memset(buffer, 0, sizeof(buffer));
int ret = recv(sock, buffer, sizeof(buffer) - 1, 0);
printf("收到服务器响应:%s\n", buffer);
if(ret<=0)break;
}
// 关闭套接字和清理Winsock
closesocket(sock);
WSACleanup();
return 0;
}