linux-cpp-chatroom/Experiment_1/server.cpp

76 lines
3.1 KiB
C++
Raw Permalink Normal View History

2023-03-31 16:43:54 +08:00
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <iostream>
using namespace std;
int main()
{
// 定义服务端 sockfd (套接字描述符)
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 定义服务端套接字 sockaddr_in (套接字地址结构)
struct sockaddr_in server_sockaddr;
server_sockaddr.sin_family = AF_INET; // TCP/IP 协议族
server_sockaddr.sin_port = htons(8023); // 端口号
server_sockaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // ip 地址127.0.0.1 是回环地址,相当于本机 ip
// bind (功能:为套接字绑定地址) 绑定成功返回 0 ,绑定出错返回 -1
if (bind(server_sockfd, (struct sockaddr *)&server_sockaddr, sizeof(server_sockaddr)) == -1)
{
perror("bind"); // 输出错误原因
exit(1); // 结束程序
}
// listen (将一个套接字置为监听模式,准备接收传入连接。用于服务器,指明某个套接字连接是被动的监听状态)
// 成功返回 0 ,出错返回 -1
if (listen(server_sockfd, 20) == -1)
{
perror("listen"); // 输出错误原因
exit(1); // 结束程序
}
// 客户端套接字
struct sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
// accept (功能:从已完成连接队列中取出成功建立连接的套接字,返回成功连接的套接字描述符)
// 成功返回非负描述符,出错返回 -1
int conn = accept(server_sockfd, (struct sockaddr *)&client_addr, &length);
if (conn < 0)
{
perror("connect"); // 输出错误原因
exit(1); // 结束程序
}
cout << "客户端成功连接\n";
// 接收缓冲区:定义为 1000 字节大小,最多存储 999 个字符长度的字符串,最后一个字符要留给'\0'
char buffer[1000];
// 不断接收数据
while (1)
{
// memset函数有三个参数第一个参数是要被初始化的内存区域的起始地址第二个参数是要设置的值第三个参数是要初始化的字节数
memset(buffer, 0, sizeof(buffer));
// recv (功能:接收数据,返回实际接收的数据长度出错时返回1)
int len = recv(conn, buffer, sizeof(buffer), 0);
// 客户端发送 exit 或者异常结束时,退出
if (strcmp(buffer, "exit") == 0 || len <= 0)
break;
cout << "收到客户端信息:" << buffer << endl;
}
// 套接字通常需要在完成数据传输等操作后及时关闭,以释放系统资源并避免出现一些问题,比如资源耗尽、端口占用等
// conn和server_sockfd分别表示客户端和服务器端的套接字文件描述符通过调用close函数来关闭它们
close(conn); // 关闭数据接受描述符
close(server_sockfd); // 关闭套接字
return 0;
}