目錄
TCP協議Linux多進程服務器代碼模板:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
// 信號捕捉函數
void recycleChild(int num)
{
// 資源回收
while(1)
{
int ret = waitpid(-1, NULL, WNOHANG);
if(ret == -1)
{
printf("所有的子進程回收完畢!!!\n");
break;
}
else if(ret == 0)
{
printf("剩下的子進程都還活着!!!\n");
break;
}
else
{
printf("child die, pid = %d\n", ret);
}
}
}
int main()
{
// 1. 創建用於監聽的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket");
exit(0);
}
// 2. 綁定
struct sockaddr_in addr;
addr.sin_family = AF_INET; // ipv4
addr.sin_port = htons(8989); // 字節序應該是網絡字節序
//inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
addr.sin_addr.s_addr = INADDR_ANY; // == 0, 獲取IP的操作交給了內核
int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == -1)
{
perror("bind");
exit(0);
}
// 3.設置監聽
ret = listen(fd, 100);
if(ret == -1)
{
perror("listen");
exit(0);
}
// 註冊新號捕捉
struct sigaction act;
act.sa_flags = 0;
act.sa_handler = recycleChild;
sigemptyset(&act.sa_mask);
sigaction(SIGCHLD, &act, NULL);
while(1)
{
// 4. 等待, 接受連接請求
struct sockaddr_in addrCli;
int len = sizeof(addrCli);
printf("正在焦急等待客戶端的連接...\n");
int connfd = accept(fd, (struct sockaddr*)&addrCli, &len);
if(connfd == -1)
{
if(errno == EINTR)
{
continue;
}
perror("accept");
exit(0);
}
// 成功和客戶端建立了連接
// 創建子進程
pid_t pid = fork();
if(pid == 0)
{
int num = 0;
while(1)
{
// 讀數據
char recvBuf[1024];
// 如果客戶端沒有發送數據, 默認阻塞
int ret = read(connfd, recvBuf, sizeof(recvBuf));
if(ret == -1)
{
perror("read");
break;
}
else if(ret == 0)
{
printf("客戶端已經斷開了連接...\n");
break;
}
else
{
// 打印客戶端地址信息
char ip[32];
inet_ntop(AF_INET, &addrCli.sin_addr.s_addr, ip, sizeof(ip));
printf("client IP: %s, Port: %d\n", ip, ntohs(addrCli.sin_port));
printf("客戶端說: %s\n", recvBuf);
// 寫數據
sprintf(recvBuf, "你好, 客戶端 - %d\n", num++);
write(connfd, recvBuf, strlen(recvBuf)+1);
}
}
close(connfd); // 通信
// 退出當前子進程
exit(0);
}
}
// 釋放資源
close(fd); // 監聽
return 0;
}
TCP協議Linux多線程服務器代碼模板:
編譯的時候記得加動態庫pthread庫:gcc pthread_test.c -o test.out -l pthread
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <pthread.h>
struct SockInfo
{
int fd; // 通信
pthread_t tid; // 線程ID
struct sockaddr_in addr; // 地址信息
};
struct SockInfo infos[128];
void* working(void* arg)
{
int num = 0;
while (1)
{
struct SockInfo* ptr = (struct SockInfo*)arg;
//通訊
char recvBuf[1024];
//如果客戶端沒有發數據,默認阻塞
int ret = read(ptr->fd, recvBuf, sizeof(recvBuf));
if (ret == -1)
{
perror("read");
break;
}
else if (ret == 0)
{
printf("客戶端已經斷開了連接...\n");
ptr->fd = -1;
break;
}
else
{
char ipbuf[64];
inet_ntop(AF_INET, &ptr->addr.sin_addr.s_addr, ipbuf, sizeof(ipbuf));
printf("current client: %s, port:%d\n", ipbuf, ntohs(ptr->addr.sin_port));
printf("客戶端說: %s\n", recvBuf);
// 寫數據
sprintf(recvBuf, "你好, 客戶端 - %d\n", num++);
write(ptr->fd, recvBuf, strlen(recvBuf)+1);
}
}
}
int main()
{
// 1. 創建用於監聽的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket");
exit(0);
}
// 2. 綁定
struct sockaddr_in addr;
addr.sin_family = AF_INET; // ipv4
addr.sin_port = htons(8989); // 字節序應該是網絡字節序
//inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
addr.sin_addr.s_addr = INADDR_ANY; // == 0, 獲取IP的操作交給了內核
int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == -1)
{
perror("bind");
exit(0);
}
// 3.設置監聽
ret = listen(fd, 100);
if(ret == -1)
{
perror("listen");
exit(0);
}
// 4. 等待, 接受連接請求
int len = sizeof(struct sockaddr);
// 數據初始化
int max = sizeof(infos) / sizeof(infos[0]);
for(int i=0; i<max; ++i)
{
bzero(&infos[i], sizeof(infos[i]));
infos[i].fd = -1;
infos[i].tid = -1;
}
printf("111111111111111\n");
// 父進程監聽, 子進程通信
while(1)
{
// 創建子線程
struct SockInfo* pinfo;
for(int i=0; i<max; ++i)
{
printf("fd = %d\n", infos[i].fd);
if(infos[i].fd == -1)
{
pinfo = &infos[i];
printf("i = %d\n", i);
break;
}
if(i == max-1)
{
sleep(1);
i--;
}
}
printf("正在焦急等待客戶端的連接...\n");
int connfd = accept(fd, (struct sockaddr*)&pinfo->addr, &len);
printf("parent thread, connfd: %d\n", connfd);
if(connfd == -1)
{
perror("accept");
exit(0);
}
pinfo->fd = connfd;
pthread_create(&pinfo->tid, NULL, working, pinfo);
pthread_detach(pinfo->tid);
}
// 釋放資源
close(fd); // 監聽
return 0;
}
客戶端代碼模板:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
int main()
{
// 1. 創建用於通信的套接字
int fd = socket(AF_INET, SOCK_STREAM, 0);
if(fd == -1)
{
perror("socket");
exit(0);
}
// 2. 連接服務器
struct sockaddr_in addr;
addr.sin_family = AF_INET; // ipv4
addr.sin_port = htons(8989); // 服務器監聽的端口, 字節序應該是網絡字節序
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr.s_addr);
int ret = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
if(ret == -1)
{
perror("connect");
exit(0);
}
int i = 0;
// 通信
while(1)
{
// 讀數據
char recvBuf[1024];
// 寫數據
sprintf(recvBuf, "data: %d\n", i++);
write(fd, recvBuf, strlen(recvBuf)+1);
// 如果客戶端沒有發送數據, 默認阻塞
read(fd, recvBuf, sizeof(recvBuf));
printf("recv buf: %s\n", recvBuf);
sleep(1);
}
// 釋放資源
close(fd);
return 0;
}