进程模型:
#include<stdio.h>
#include<sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include<sys/wait.h>
#include<signal.h>
#include<stdlib.h>
#define ERR(msg) {\
fprintf(stderr,"__%d__:",__LINE__);\
perror(msg);}
#define PORT 8888
#define IP "192.168.31.175"
typedef void(*sighandler_t)(int);
int rcv_cli_msg(int newfd,struct sockaddr_in cin);
void handler(int sig)
{
while(waitpid(-1,NULL,WNOHANG)>0);
}
int main(int argc, const char *argv[])
{
//捕获17号信号,用信号的方式回收僵尸进程
sighandler_t s = signal(SIGCHLD,handler);
if(SIG_ERR == s)
{
ERR("signal17");
return -1;
//接收客户端消息
//向客户端传递消息
//定义数组存放接收到的客户端消息,接收返回值用res存放
char buf[128]="";
ssize_t res=0;
}
//创建流式套接字,用于tcp通信
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(sfd<0)
{
perror("socket");
return -1;
}
//允许端口快速重用
int reuse = 1;
if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))<0)
{
ERR("setsockopt");
return -1;
}
//填充地址信息结构体,此步骤相当于办手机卡
//定义结构体类型存放服务器的端口IP相关信息
struct sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
//主机端口转网络字节序,服务器端口范围1024~49151
//临时端口号:49152~65535,这部分是客户端运行时候动态选择的
sin.sin_addr.s_addr = inet_addr(IP);
//绑定端口和IP作为服务器的地址
if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin))<0)
{
ERR("bind");
return -1;
}
//设置服务器的监听状态
if(listen(sfd,10)<0)
{
//接收客户端消息
//向客户端传递消息
//定义数组存放接收到的客户端消息,接收返回值用res存放
char buf[128]="";
ssize_t res=0;
ERR("listen");
return -1;
}
//定义结构体存放,客户端的IP和端口
struct sockaddr_in cin;
socklen_t addrlen = sizeof(cin);
//阻塞连接,可设置非阻塞,及超时状态,等待客户端连接
int newfd;
pid_t pid;
while(1)
{
newfd= accept(sfd,(struct sockaddr*)&cin,&addrlen);
if(newfd < 0) // 或 == -1
{
ERR("accept");
return -1;
}
printf("客户端连接成功\n");
//inet_ntoa 网络地址转主机地址 ntohs 网络端口转主机端口
printf("[%s:%d] newfd = %d\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);
//此时创建一个子进程,与客户端交互
pid = fork();
if(0==pid)
{
close(sfd); //sfd做连接,父进程不需要可以关闭
rcv_cli_msg(newfd,cin); //调用交互函数
close(newfd);//完成交互,关闭文退出
exit(0);
}
else if(pid>0)
{
close(newfd);
}
else
{
ERR("fork");
return -1;
}
}
//关闭套接字
close(sfd);
return 0;
}
int rcv_cli_msg(int newfd,struct sockaddr_in cin)
{
//将客户端的文件描述符和地址信息传过来
//接收客户端消息
//向客户端传递消息
//定义数组存放接收到的客户端消息,接收返回值用res存放
char buf[128]="";
ssize_t res=0;
while(1)
{
//接收前清空
bzero(buf,sizeof(buf));
res=recv(newfd,buf,sizeof(buf),0);
if(res<0)
{
ERR("recv");
return -1;
}
else if(0==res)
{
fprintf(stderr,"[%s:%d]newfd=%d客户端关闭\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
break;
}
printf("[%s:%d] newfd=%d:%s\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd,buf);
strcat(buf,"....");
if(send(newfd,buf,sizeof(buf),0)<0)
{
ERR("send");
return -1;
}
printf("发送成功\n");
}
return 0;
}
ubu
//每次连接客户端的newfd都是4,因为子进程交互完就关闭了文件描述符,所以下次连接还可以从4开始。
线程创建:
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#define IP "192.168.31.197"
#define ERR_MSG(msg) do{\
fprintf(stderr, "__%d__", __LINE__);\
perror(msg);\
}while(0)
void* callback(void* arg);
struct msg
{
int newfd;
struct sockaddr_in sed;
};
int main(int argc, const char *argv[])
{
//创建流式套接字
int sfd = socket(AF_INET,SOCK_STREAM, 0);
if(sfd<0)
{
ERR_MSG("socket");
return -1;
}
//允许端口快速重用
int reuse=1;
if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse))<0)
{
ERR_MSG("setsockopt");
return -1;
}
printf("允许端口快速重用设置成功\n");
//填充ip和端口到地址信息结构体中
struct sockaddr_in sin;
sin.sin_family =AF_INET;
sin.sin_port =htons(8888);
sin.sin_addr.s_addr =inet_addr(IP);
//绑定服务器的ip端口和地址,必须绑定
if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin))<0)
{
ERR_MSG("bind");
return -1;
}
//将套接字设置为被动监听状态
if(listen(sfd, 10)<0)
{
ERR_MSG("listen");
return -1;
}
printf("listen succes\n");
struct sockaddr_in sed;
int a=sizeof(sed);
pthread_t tid;
struct msg info;
while(1)
{
int newfd=accept(sfd, (struct sockaddr*)&sed, &a);
if(newfd<0)
{
ERR_MSG("accept");
return -1;
}
printf("newfd=%d\n", newfd);
info.newfd=newfd;
info.sed=sed;
pthread_create(&tid, NULL, callback, (void*)&info);
pthread_detach(tid);
}
close(sfd);
return 0;
}
void* callback(void* arg)
{
struct msg info=*(struct msg*)arg;
int newfd = info.newfd;
struct sockaddr_in sed=info.sed;
char buf[128]="";
ssize_t res=0;
while(1)
{
bzero(buf, sizeof(buf));
//接收
res=recv(newfd, buf, sizeof(buf), 0);
if(res<0)
{
ERR_MSG("recv");
break;
}
else if(0==res)
{
fprintf(stderr, "newfd=%d客户端关闭\n", newfd);
break;
}
printf("newfd=%d : %s\n", newfd, buf);
//发送
strcat(buf, "*_*");
if(send(newfd,buf, sizeof(buf),0)<0 )
{
ERR_MSG("send");
break;
}
printf("发送成功\n");
}
close(newfd);
pthread_exit(NULL);
return 0;
}