C/C++ TCP服務器案例代碼,客戶端業務都新開線程處理,不能用於生產環境,生產環境使用select/epool,或開源庫libevent、asio等處理
TCP服務端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <thread>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("usage: ./server <port>\n");
return EXIT_FAILURE;
}
int server_socket_fd;
struct sockaddr_in server_addr;
int on = 1;
if ((server_socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return EXIT_FAILURE;
}
if (setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
{
printf("setsockopt error: %s\n", strerror(errno));
return EXIT_FAILURE;
}
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(6666);
if (bind(server_socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1)
{
printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
if (listen(server_socket_fd, 10) == -1)
{
printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);
return 0;
}
printf("======waiting for client's request======\n");
for (;;)
{
struct sockaddr_in client_addr;
socklen_t address_len = sizeof(client_addr);
int accept_fd; //客戶端連接Socket_FD
if ((accept_fd = accept(server_socket_fd, (struct sockaddr *)&client_addr, &address_len)) != -1)
{
//打印客戶端連接地址
printf("client address: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
//客戶端後臺線程處理業務,避免阻塞主線程,導致主線程無法接收新的客戶端鏈接
std::thread client_thread([accept_fd, client_addr]() {
for (;;)
{
char buff[BUF_SIZE];
memset(buff, '\0', sizeof(buff));
int size = recv(accept_fd, buff, sizeof(buff), 0);
if (size <= 0)
{
printf("client disconnected: %s:%d\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
close(accept_fd);
break;
}
printf("recv msg from client: %s\n", buff);
send(accept_fd, buff, sizeof(buff), 0);
printf("send msg to client: %s\n", buff);
}
});
client_thread.detach(); //客戶端業務後臺線程,避免註冊主線程監聽新的客戶端連接
}
else
{
printf("accept socket error: %s\n", strerror(errno));
continue;
}
}
close(server_socket_fd);
return 0;
}
TCP客戶端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define BUF_SIZE 1024
int main(int argc, char **argv)
{
int socket_fd, size;
char recvline[BUF_SIZE], sendline[BUF_SIZE];
struct sockaddr_in servaddr;
if (argc != 3)
{
printf("usage: ./client <ipaddress> <port>\n");
return EXIT_FAILURE;
}
const char *host = argv[1];
int port = atoi(argv[2]);
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);
return EXIT_FAILURE;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
if (inet_pton(AF_INET, host, &servaddr.sin_addr) <= 0)
{
printf("inet_pton error for %s\n", host);
return EXIT_FAILURE;
}
if (connect(socket_fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
printf("connect error: %s(errno: %d)\n", strerror(errno), errno);
return EXIT_FAILURE;
}
printf("send msg to tcp server: \n");
for (;;)
{
memset(sendline, '\0', sizeof(sendline));
memset(recvline, '\0', sizeof(recvline));
fgets(sendline, BUF_SIZE, stdin);
if (send(socket_fd, sendline, strlen(sendline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
close(socket_fd);
}
if (recv(socket_fd, recvline, sizeof(recvline), 0) < 0)
{
printf("send msg error: %s(errno: %d)\n", strerror(errno), errno);
close(socket_fd);
break;
}
printf("receive from tcp server: %s\n", recvline);
}
close(socket_fd);
return EXIT_SUCCESS;
}
客戶端效果:
send msg to tcp server:
zhangsan
receive from tcp server: zhangsan
lisi
receive from tcp server: lisi
wangwu
receive from tcp server: wangwu
服務端效果:
recv msg from client: zhangsan
send msg to client: zhangsan
recv msg from client: lisi
send msg to client: lisi
recv msg from client: wangwu
send msg to client: wangwu