- C++:使用C++语言进行编程,包括使用C++标准库和相关的数据类型、函数等。
- Socket编程:基于套接字(Socket)的网络通信,通过创建套接字、绑定地址、监听连接请求、接受客户端连接等操作来建立服务器端。
- Linux环境:在Linux操作系统下进行开发,使用相应的系统调用和头文件。
- 网络协议:基于TCP/IP协议栈进行通信,使用TCP协议实现可靠的数据传输
实际的网络编程可能还涉及其他高级技术和功能,例如多线程处理、非阻塞IO、异步编程、网络安全等,具体根据需求进行扩展和优化。
编写思路
- 导入所需的头文件:
-
#include <iostream> #include <sys/socket.h> #include <netinet/in.h>//网络通信TCP/IP协议 #include <unistd.h>
-
创建套接字:
-
int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd == -1) { std::cout << "Failed to create socket" << std::endl; return -1; }
-
设置服务器地址和端口:
-
sockaddr_in serverAddress{}; serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = INADDR_ANY; serverAddress.sin_port = htons(port); // 设置端口号 if (bind(sockfd, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) { std::cout << "Binding failed" << std::endl; return -1; }
-
监听连接请求:
-
if (listen(sockfd, backlog) < 0) { std::cout << "Listening failed" << std::endl; return -1; }
-
接受客户端连接:
-
sockaddr_in clientAddress{}; socklen_t clientAddressLength = sizeof(clientAddress); int clientSocket = accept(sockfd, (struct sockaddr*)&clientAddress, &clientAddressLength); if (clientSocket < 0) { std::cout << "Accepting connection failed" << std::endl; return -1; }
-
和客户端进行通信: 在这一步可以根据具体需求编写代码来处理和客户端之间的通信。可以使用
clientSocket
来发送和接收数据。 -
关闭套接字:
close(clientSocket); close(sockfd);
请注意,在Linux环境下,可能还需要添加适当的权限和设置防火墙规则,以确保网络连接正常。
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <list>
using namespace std;
#define _PORT_ 2022
#define _BACKLOG_ 10
// 客服连接到服务器后,需要先登录,发送登录消息:
// name字符串,不能含有空格
struct client {
public:
int socket;
char name[32];
char ip[16];
bool operator==(const client &other) const {
return other.socket == socket;
}
};
list<client> clients;
void showClients() {
printf("\n\n***********show all clients********\n");
int k=0;
for(auto it=clients.begin(); it != clients.end(); it++) {
printf("NO.%d name:[%s] socket:[%d]\n", ++k, it->name, it->socket);
}
printf("\n*********************************** \n\n");
}
void* client_func(void *arg) {
client *p = (client*)arg;
// regist
char buf[1024];
char buff2[1024];
memset(buf,'0',sizeof(buf));//跟前面的初始化对比
if (read(p->socket, buf, sizeof(buf)) <= 0) {
delete p;
return NULL;
}
printf("Receive register info: %s\n",buf);
sscanf(buf, "%s", p->name);
sprintf(buf, "【%s@%s】进入聊天室", p->ip, p->name);
clients.push_back(*p);
printf("Add a new client. count=%d\n", clients.size());
//showClients();
printf("clients size = %d\n", clients.size());
int k=0;
for(auto it=clients.begin(); it != clients.end(); it++) {
printf("send no.%d client\n", ++k);
write(it->socket, buf, strlen(buf)+1);
}
//clients.push_back(*p);
while(1) {
int ret = read(p->socket, buf, sizeof(buf));
if (ret <= 0) {
break;
}
printf("client :# %s\n",buf);
sprintf(buff2, "【%s@%s】%s", p->ip, p->name, buf);
for(auto it=clients.begin(); it != clients.end(); it++) {
if (it->socket != p->socket) {
write(it->socket, buff2, strlen(buff2)+1);
}
}
}
clients.remove(*p);
delete p;
return NULL;
}
int main()
{
int sock = socket(AF_INET,SOCK_STREAM,0);
struct sockaddr_in server_socket;
struct sockaddr_in client_socket;
bzero(&server_socket,sizeof(server_socket));
server_socket.sin_family = AF_INET;
server_socket.sin_port = htons(_PORT_);
server_socket.sin_addr.s_addr = htonl(INADDR_ANY);
bind(sock,(struct sockaddr *)&server_socket,sizeof(struct sockaddr_in));
listen(sock,_BACKLOG_);
while(1) {
socklen_t len = sizeof(client_socket);
printf("wait accept...\n");
int client_sock = accept(sock,(struct sockaddr *)&client_socket,&len);
if(client_sock < 0) {
printf("accept error, error is %d,errstring is %s\n",errno,strerror(errno));
close(sock);
return 3;
}
client *c = new client;
strcpy(c->ip, inet_ntoa(client_socket.sin_addr));
printf("get connect,ip is %s\n", c->ip);
c->socket = client_sock;
pthread_t tid;
pthread_create(&tid, NULL, client_func, (void*)c);
}
close(sock);
return 0;
}