一 多线程服务器:
服务器代码实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#define PORT 9999
//初始化套接字
int INIT_SCOKET()
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1)
{
perror ("socket");
return -1;
}
// 2、命名套接字,绑定本地的ip地址和端口
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; // 设置地址族
addr.sin_port = htons(PORT); // 设置本地端口
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用本地的任意IP地址
int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror ("bind");
return -1;
}
// 3、监听本地套接字
ret = listen(listen_socket, 5);
if (ret == -1)
{
perror ("listen");
return -1;
}
printf ("等待客户端连接.......\n");
return listen_socket;
}
// 4、接收连接
int MY_ACCEPT(int listen_socket)
{
// 监听套接字不能用来与客户端进行通信,它的职责是监听客户端的连接
// accpet 处理客户端的连接,如果成功接收,会返回一个新的套接字,用来与客户端进行通信
// accept的第三个参数 是一个传入传出参数
struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息
int len = sizeof(client_addr);
int client_socket = accept(listen_socket,(struct sockaddr *)&client_addr,&len);
if (client_socket == -1)
{
perror ("accept");
}
printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));
return client_socket;
}
//把负责处理客户端通信的函数作为线程的工作函数
void * HANDLE (void *v)
{
int client_socket = (int)v;
char buf[1024];
int i;
while (1)
{
//从客户端读取数据
int ret = read(client_socket, buf, 1024);
if(ret == -1)
{
perror("read ");
break;
}
if(ret == 0)
{
printf("客户端断开\n");
break;
}
buf[ret] = '\0';
for(i = 0;i < ret - 1; i++)
{
buf[i] = buf[i] + 'A' - 'a';
}
write (client_socket, buf, ret);
printf ("发送数据 :%s\n", buf);
}
close(client_socket);
}
int main()
{
int listen_socket = INIT_SCOKET();//1、创建socket
while(1)
{
//获取与客户端连接的套接字
int client_socket = MY_ACCEPT(listen_socket);
//创建线程去处理客户端的请求,主线程负责监听
pthread_t thread_id;
pthread_create(&thread_id,NULL,HANDLE,(void *)client_socket);
pthread_detach(thread_id); //线程分离
}
close(listen_socket);
return 0;
}
客户端代码实现:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#define PORT 9999
//请求服务
int ASK(int socket_fd)
{
char buf[1024];
while(1)
{
fgets(buf,1024,stdin);
if(strncmp(buf, "end", 3) == 0)
{
break;
}
write(socket_fd,buf,strlen(buf));
int ret = read(socket_fd,buf,1023);
if(ret == -1)
{
perror("read ");
return -1;
}
buf[ret] = '\0';
printf("buf : %s\n",buf);
}
}
//int socket(int domain, int type, int protocol);
int main()
{
//初始化套接字
int socket_fd = socket(AF_INET,SOCK_STREAM,0);
if(socket_fd == -1)
{
perror("socket ");
return -1;
}
//命名套接字,绑定本地IP地址和端口
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));//将整个结构体清零
//结构体成员初始化
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
inet_aton("127.0.0.1",&(addr.sin_addr));
// int connect(int sockfd, const struct sockaddr*serv_addr, socklen_t addrlen);
int ret = connect(socket_fd,(struct sockaddr *)&addr,sizeof(addr));
if(ret == -1)
{
perror("connect ");
return -1;
}
printf("成功连接服务器\n");
ASK(socket_fd);
close(socket_fd);
return 0;
}
二 多进程服务器:
客户端代码可与上述代码共用,
多进程服务器代码实现:
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdlib.h>
#define PORT 9999
//初始化套接字
int INIT_SCOKET()
{
int listen_socket = socket(AF_INET, SOCK_STREAM, 0);
if (listen_socket == -1)
{
perror ("socket");
return -1;
}
// 2、命名套接字,绑定本地的ip地址和端口
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET; // 设置地址族
addr.sin_port = htons(PORT); // 设置本地端口
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 使用本地的任意IP地址
int ret = bind(listen_socket, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror ("bind");
return -1;
}
// 3、监听本地套接字
ret = listen(listen_socket, 5);
if (ret == -1)
{
perror ("listen");
return -1;
}
printf ("等待客户端连接.......\n");
return listen_socket;
}
//接收连接
int MY_ACCEPT(int listen_socket)
{
// 监听套接字不能用来与客户端进行通信,它的职责是监听客户端的连接
// accpet 处理客户端的连接,如果成功接收,会返回一个新的套接字,用来与客户端进行通信
// accept的第三个参数 是一个传入传出参数
struct sockaddr_in client_addr; // 用来保存客户端的ip和端口信息
int len = sizeof(client_addr);
int client_socket = accept(listen_socket,(struct sockaddr *)&client_addr,&len);
if (client_socket == -1)
{
perror ("accept");
return -1;
}
printf ("成功接收一个客户端: %s\n", inet_ntoa(client_addr.sin_addr));
return client_socket;
}
//处理客户端链接
void HANDLE (int client_socket)
{
char buf[1024];
while (1)
{
int ret = read(client_socket, buf, 1024);
if(ret == -1)
{
perror("read ");
break;
}
if(ret == 0)
{
printf("客户端断开\n");
break;
}
buf[ret] = '\0';
int i;
for(i = 0;i < ret - 1; i++)
{
buf[i] = buf[i] + 'A' - 'a';
}
write (client_socket, buf, ret);
printf ("发送数据 : %s\n", buf);
}
close(client_socket);
}
// 处理子进程的退出
void handle(int sig)
{
while (waitpid(-1, NULL, WNOHANG) > 0)
{
printf("成功处理一个子进程的退出\n");
}
}
int main()
{
int listen_socket = INIT_SCOKET();//1、创建socket
//处理子进程的退出
signal (SIGCHLD, handle);
while(1)
{
//获取与客户端连接的套接字
int client_socket = MY_ACCEPT(listen_socket);
int ret = fork();
if(ret == -1)
{
perror("fork");
return -1;
}
if(ret > 0)//父进程
{
close(client_socket);//关闭连接套接字
continue;
}
if(ret == 0)//子进程
{
close(listen_socket);//关闭监听套接字
HANDLE(client_socket);
exit(0);
}
}
close(listen_socket);
return 0;
}
编译结果: