本文主要是介绍2.11...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
多进程
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <head.h>#define PORT 8888 //1024~49151
#define IP "192.168.122.120" //ifconfig查看本机IPint deal_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) SIGCHLD信号if(signal(17, handler) == SIG_ERR){ERR_MSG("signal");return -1;}printf("捕获成功\n");//创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0);if(sfd < 0){ERR_MSG("socket");return -1;}printf("sfd = %d\n", sfd);//设置允许端口被快速复用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ERR_MSG("setsockopt");return -1;}printf("允许端口快速重用成功\n");//填充地址信息结构体,真实的地址信息结构体根据地址族指定//AF_INET: man 7 ipstruct sockaddr_in sin;sin.sin_family = AF_INET; //必须填AF_INETsin.sin_port = htons(PORT); //端口号:1024~49151sin.sin_addr.s_addr = inet_addr(IP); //本机IP ifconfig查看//绑定服务器的IP和端口--->必须绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0){ERR_MSG("bind");return -1;}printf("bind success \n");//将套接字设置为被动监听状态if(listen(sfd, 128) < 0){ERR_MSG("listen");return -1;}printf("listen success\n");struct sockaddr_in cin; //存储客户端的地址信息socklen_t addrlen = sizeof(cin);int newfd = -1;pid_t cpid = 0;while(1){//父进程只负责连接//从已完成连接的队列中获取一个客户端信息,生成一个新的文件描述符//该文件描述符才是与客户端通信的文件描述符newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("[%s : %d] newfd=%d 客户端连接成功\n", \inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);//能运行到当前位置,则代表有客户端连接成功,此时需要创建一个子进程,专门用于交互cpid = fork();if(0 == cpid) //子进程中为真{close(sfd); //子进程只负责交互,所以sfd对于子进程而言没有用deal_cli_msg(newfd, cin);exit(0); //交互结束后,必须要退出子进程}close(newfd); //父进程只负责连接,所以newfd对于父进程而言没有用}//关闭所有文件描述符close(sfd);return 0;
}int deal_cli_msg(int newfd, struct sockaddr_in cin)
{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");return -1;}else if(0 == res){printf("[%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_MSG("send");return -1;}printf("send success\n");}close(newfd);return 0;
}
多线程
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <pthread.h>
#include <head.h>#define PORT 8888 //1024~49151
#define IP "192.168.122.120" //ifconfig查看本机IP//需要传入到分支线程的数据类型
struct Climsg
{int newfd;struct sockaddr_in cin;
};void* deal_cli_msg(void* arg); //void* arg = (void*)&infoint main(int argc, const char *argv[])
{//创建流式套接字int sfd = socket(AF_INET, SOCK_STREAM, 0); if(sfd < 0){ ERR_MSG("socket");return -1; } printf("sfd = %d\n", sfd);//设置允许端口被快速复用int reuse = 1;if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0){ ERR_MSG("setsockopt");return -1; } printf("允许端口快速重用成功\n");//填充地址信息结构体,真实的地址信息结构体根据地址族指定//AF_INET: man 7 ipstruct sockaddr_in sin;sin.sin_family = AF_INET; //必须填AF_INETsin.sin_port = htons(PORT); //端口号:1024~49151sin.sin_addr.s_addr = inet_addr(IP); //本机IP ifconfig查看//绑定服务器的IP和端口--->必须绑定if(bind(sfd, (struct sockaddr*)&sin, sizeof(sin)) < 0){ ERR_MSG("bind");return -1; } printf("bind success \n");//将套接字设置为被动监听状态if(listen(sfd, 128) < 0){ ERR_MSG("listen");return -1; } printf("listen success\n");struct sockaddr_in cin; //存储客户端的地址信息socklen_t addrlen = sizeof(cin);int newfd = -1; pthread_t tid;struct Climsg info;while(1){ newfd = accept(sfd, (struct sockaddr*)&cin, &addrlen);if(newfd < 0){ERR_MSG("accept");return -1;}printf("[%s : %d] newfd=%d 客户端连接成功\n", \inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), newfd);info.newfd = newfd;info.cin = cin;//能运行到当前位置,则代表有客户端连接成功,需要创建一个分支线程只负责交互if(pthread_create(&tid, NULL, deal_cli_msg, (void*)&info) != 0){fprintf(stderr, "pthread_create failed __%d__\n", __LINE__);return -1; }pthread_detach(tid); //分离线程} //关闭所有文件描述符close(sfd);return 0;
}//线程执行体
void* deal_cli_msg(void* arg) //void* arg = (void*)&info
{//newfd必须另存。不允许使用全局变量,或者所有线程通过指针的方式一直访问同一块空间//因为一旦有多个客户端连接到服务器,会导致全局变量的newfd被覆盖int newfd = ((struct Climsg*)arg)->newfd;struct sockaddr_in cin = ((struct Climsg*)arg)->cin;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){printf("[%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_MSG("send");break;}printf("send success\n");} close(newfd);pthread_exit(NULL);
}
这篇关于2.11...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!