目录
一、循环服务器
#include <myhead.h>
#define SER_PORT 6666
#define SER_IP "192.168.232.129"
int main(int argc, char const *argv[])
{
// 1、创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 参数1:ipv4的网络通信
// 参数2:TCP通信方式
// 参数3:默认使用一个协议
if (sfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success, sfd = %d\n", sfd); // 3
// 2、为套接字绑定ip地址和端口号
// 2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; // 通信域
sin.sin_port = htons(SER_PORT); // 端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); // ip地址
// 2.2 绑定
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
// 3、将套接字设置为被动监听状态,用于接收
if (listen(sfd, 128) == -1)
{
perror("listen error");
return -1;
}
printf("listen success\n");
// 4、阻塞等待客户端的连接请求
// 4.1 定义n变量用于e接收客服端的信息
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while (1) // 循环服务器
{
// 4.2 接收连接
int newsfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);
if (newsfd == -1)
{
perror("accept error");
return -1;
}
printf("[%s:%d]:accept on\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port));
// 5、数据收发
char buf[128] = "";
while (1)
{
// 从客户端套接字中接收数据
int res = recv(newsfd, buf, sizeof(buf), 0);
if (res == -1)
{
perror("read error");
return -1;
}
else if (res == 0)
{
printf("客户端已下线\n");
close(newsfd); // 关闭客户端套接字
break;
}
// 接收数据
printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
// 对接收到的数据进行处理
strcat(buf, ":D");
// 将消息返回到客户端
if (send(newsfd, buf, strlen(buf), 0) == -1)
{
perror("发送失败\n");
return -1;
}
printf("发送成功\n");
bzero(buf, sizeof(buf)); // 清空容器
}
}
close(sfd);
close(newsfd);
return 0;
}
二、进程实现TCP并发服务器
#include <myhead.h>
#define SER_PORT 6666
#define SER_IP "192.168.232.129"
void handler(int signo)
{
if (signo == SIGCHLD)
{
while (waitpid(-1, NULL, WNOHANG) > 0);
}
}
int main(int argc, char const *argv[])
{
// 将子进程退出时的 SIGCHID 信号绑定到信号处理函数中
if (signal(SIGCHLD, handler) == SIG_ERR)
{
perror("signal error");
return -1;
}
// 1、创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 参数1:ipv4的网络通信
// 参数2:TCP通信方式
// 参数3:默认使用一个协议
if (sfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success, sfd = %d\n", sfd); // 3
// 2、为套接字绑定ip地址和端口号
// 2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; // 通信域
sin.sin_port = htons(SER_PORT); // 端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); // ip地址
// 2.2 绑定
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
// 3、将套接字设置为被动监听状态,用于接收
if (listen(sfd, 128) == -1)
{
perror("listen error");
return -1;
}
printf("listen success\n");
// 4、阻塞等待客户端的连接请求
// 4.1 定义变量用于e接收客服端的信息
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
while (1) // 循环服务器
{
// 4.2 接收连接
int newsfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);
if (newsfd == -1)
{
perror("accept error");
return -1;
}
printf("[%s:%d:%d]:accept on\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newsfd);
pid_t pid = fork(); // 创建子进程 用于 与客服端通信
if (pid > 0)
{
// 关闭父进程的 newsfd
close(newsfd);
}
else if (pid == 0)
{
// 关闭子进程的 sfd
close(sfd);
// 5、数据收发
char buf[128] = "";
while (1)
{
// 从客户端套接字中接收数据
int res = recv(newsfd, buf, sizeof(buf), 0);
if (res == -1)
{
perror("read error");
return -1;
}
else if (res == 0)
{
printf("客户端已下线\n");
close(newsfd); // 关闭客户端套接字
break;
}
// 接收数据
printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
// 对接收到的数据进行处理
strcat(buf, ":D");
// 将消息返回到客户端
if (send(newsfd, buf, strlen(buf), 0) == -1)
{
perror("发送失败\n");
return -1;
}
printf("发送成功\n");
bzero(buf, sizeof(buf)); // 清空容器
}
// 退出子进程
exit(EXIT_SUCCESS);
}
}
close(sfd);
return 0;
}
三、进程实现TCP并发服务器
#include <myhead.h>
#define SER_PORT 6666
#define SER_IP "192.168.232.129"
// 用于信息传递的结构体
struct MsgInfo
{
int newsfd;
struct sockaddr_in cin;
};
// 线程体函数
void *deal_cli_msg(void *arg)
{
// 解析主线程传递数据
int newsfd = (*(struct MsgInfo *)arg).newsfd;
struct sockaddr_in cin = (*(struct MsgInfo *)arg).cin;
// 5、数据收发
char buf[128] = "";
while (1)
{
// 从客户端套接字中接收数据
int res = recv(newsfd, buf, sizeof(buf), 0);
if (res == -1)
{
perror("read error");
return NULL;
}
else if (res == 0)
{
printf("客户端已下线\n");
close(newsfd); // 关闭客户端套接字
break;
}
// 接收数据
printf("[%s:%d]:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), buf);
// 对接收到的数据进行处理
strcat(buf, ":D");
// 将消息返回到客户端
if (send(newsfd, buf, strlen(buf), 0) == -1)
{
perror("发送失败\n");
return NULL;
}
printf("发送成功\n");
bzero(buf, sizeof(buf)); // 清空容器
}
// 退出线程
pthread_exit(NULL);
}
int main(int argc, char const *argv[])
{
// 1、创建套接字
int sfd = socket(AF_INET, SOCK_STREAM, 0);
// 参数1:ipv4的网络通信
// 参数2:TCP通信方式
// 参数3:默认使用一个协议
if (sfd == -1)
{
perror("socket error");
return -1;
}
printf("socket success, sfd = %d\n", sfd); // 3
// 2、为套接字绑定ip地址和端口号
// 2.1 填充地址信息结构体
struct sockaddr_in sin;
sin.sin_family = AF_INET; // 通信域
sin.sin_port = htons(SER_PORT); // 端口号
sin.sin_addr.s_addr = inet_addr(SER_IP); // ip地址
// 2.2 绑定
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
{
perror("bind error");
return -1;
}
printf("bind success\n");
// 3、将套接字设置为被动监听状态,用于接收
if (listen(sfd, 128) == -1)
{
perror("listen error");
return -1;
}
printf("listen success\n");
while (1)
{
// 4、阻塞等待客户端的连接请求
// 4.1 定义n变量用于e接收客服端的信息
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
// 4.2 接收连接
int newsfd = accept(sfd, (struct sockaddr *)&cin, &addrlen);
if (newsfd == -1)
{
perror("accept error");
return -1;
}
printf("[%s:%d:%d]:accept on\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newsfd);
// 定义结构体变量
struct MsgInfo buf = {newsfd, cin};
pthread_t tid = -1;
if(pthread_create(&tid, NULL, deal_cli_msg, &buf) != 0)
{
printf("pthread_create error\n");
return -1;
}
// 主线程回收子线程资源
pthread_detach(tid); // 将线程设置为分离态
}
close(sfd);
// close(newsfd);
return 0;
}