主线程读socket,子线程写socket
#include <arpa/inet.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
void* chat_send(void* param) {
// 以下操作没有改变默认选项
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, nullptr);
int client_socket = *(int*)param;
while (true) {
char buf[1024];
std::memset(buf, 0, sizeof(buf));
std::scanf("%s", buf);
send(client_socket, buf, strlen(buf), 0); // 此处是一个 cancellation point 可免去 pthread_testcancel();
}
}
int main(int argc, char const* argv[]) {
int server_socket = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in server_address;
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8081);
server_address.sin_addr.s_addr = inet_addr("0.0.0.0");
bind(server_socket, (sockaddr*)&server_address, sizeof(server_address));
listen(server_socket, 1);
int client_socket = accept(server_socket, nullptr, 0);
if (client_socket < 0) {
std::perror("accept failed");
}
pthread_t send_thread_id;
pthread_create(&send_thread_id, nullptr, chat_send, &client_socket);
while (true) {
char buf[1024];
int n = recv(client_socket, &buf, 1024, 0);
if (n <= 0) {
std::printf("recv %d, disconnect\n", n);
break;
}
buf[n] = '\0';
std::printf("\r[out:] >> %s\n", buf);
}
pthread_cancel(send_thread_id);
close(client_socket);
return 0;
}
多进程服务端
#include <errno.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <cstdio>
#include <cstring>
int main(int argc, char const *argv[]) {
struct sockaddr_in server_address, client_address;
socklen_t client_address_len;
char buf[1024];
auto s = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(8081);
bind(s, (struct sockaddr *)&server_address, sizeof(server_address));
listen(s, 1);
while (true) {
client_address_len = sizeof(client_address);
auto client =
accept(s, (struct sockaddr *)&client_address, &client_address_len);
if (client == -1) {
std::perror("servcer accept failed!");
_exit(1);
}
std::printf("accept %d, client: %d\n",
ntohl(client_address.sin_addr.s_addr), client);
// 屏蔽 SIGCLD 信号,让内核回收子进程资源
signal(SIGCLD, SIG_IGN);
pid_t pid = fork();
if (pid != 0) {
std::printf("fork sub process %d\n", pid);
} else {
while (true) {
// 使用 select 实现超时检测和检查是否断开
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(client, &read_fds);
// struct timeval timeout;
// timeout.tv_sec = 3;
auto nselect = select(FD_SETSIZE, &read_fds, nullptr, nullptr, nullptr);
if (nselect == -1) {
perror(strcat("select failed", std::strerror(errno)));
}
if (nselect == 0) {
printf("没有可读文件描述符\n");
break;
}
auto nrecv = read(client, buf, sizeof(buf));
if (nrecv == -1) {
std::printf("nrecv: %ld\n", nrecv);
perror(std::strerror(errno));
goto NEXTACCEPT;
} else if (nrecv == 0) {
std::printf("nrecv: 0, 连接 %d 已断开\n", getpid());
goto NEXTACCEPT;
}
buf[nrecv] = '\0';
std::printf("recv %ld from %d : %s\n", nrecv, getpid(), buf);
}
NEXTACCEPT:
close(client);
_exit(0);
}
}
return 0;
}
多线程服务端
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
void *socket_deal(void *);
int main(int argc, char const *argv[]) {
struct sockaddr_in server_address, client_address;
socklen_t client_address_len;
auto s = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(8081);
bind(s, (struct sockaddr *)&server_address, sizeof(server_address));
listen(s, 1);
while (true) {
client_address_len = sizeof(client_address);
auto client =
accept(s, (struct sockaddr *)&client_address, &client_address_len);
if (client == -1) {
std::perror("servcer accept failed!");
_exit(1);
}
std::printf("accept %d, client: %d\n",
ntohl(client_address.sin_addr.s_addr), client);
int *param = new int;
*param = client;
pthread_t thread_id;
pthread_create(&thread_id, nullptr, socket_deal, param);
pthread_detach(thread_id);
std::printf("create thread %ld to deal socket\n", pthread_self());
}
return 0;
}
void *socket_deal(void *client_point) {
int client = *(int *)client_point;
delete (int *)client_point;
char buf[1024];
while (true) {
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(client, &read_fds);
// struct timeval timeout;
// timeout.tv_sec = 3;
auto nselect = select(FD_SETSIZE, &read_fds, nullptr, nullptr, nullptr);
if (nselect == -1) {
perror(strcat("select failed", std::strerror(errno)));
}
if (nselect == 0) {
printf("没有可读文件描述符\n");
break;
}
auto nrecv = read(client, buf, sizeof(buf));
if (nrecv == -1) {
std::printf("nrecv: %ld\n", nrecv);
perror(std::strerror(errno));
goto NEXTACCEPT;
} else if (nrecv == 0) {
std::printf("nrecv: 0, 连接 %ld 已断开\n", pthread_self());
goto NEXTACCEPT;
}
buf[nrecv] = '\0';
std::printf("recv %ld from %ld : %s\n", nrecv, pthread_self(), buf);
}
NEXTACCEPT:
close(client);
return nullptr;
}
客户端
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
int main(int argc, char const *argv[]) {
sockaddr_in server_address;
char buf[1024];
std::memset(buf, 0, 1024);
int server = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_port = htons(8081);
server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(server, (sockaddr *)&server_address, sizeof(server_address)) <
0) {
std::perror("connect failed!");
_exit(1);
}
while (true) {
std::memset(buf, 0, 1024);
printf("[input] >> ");
std::scanf("%s", buf);
int n = send(server, buf, strlen(buf), 0);
printf("send's length: %d\n", n);
if (n < 0) {
std::perror("send failed!");
close(server);
_exit(1);
}
}
close(server);
return 0;
}