
【LINUX网络编程】Socket网络编程实战
发布日期:2021-05-08 05:10:19
浏览次数:13
分类:原创文章
本文共 13912 字,大约阅读时间需要 46 分钟。
网络套接字函数
最简单的socket的程序
sever
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <ctype.h>#define MAXLINE 80#define PORT 6666int main(void){ struct sockaddr_in servaddr,cliaddr; socklen_t cliaddr_len; int listenfd,connfd; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i,n; listenfd =socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,20); printf("Accepting connections ...\n"); while (1) { cliaddr_len =sizeof(cliaddr); connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); n=read(connfd,buf,MAXLINE); printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); for (int i = 0; i < n; i++)buf[i] =toupper(buf[i]); write(connfd,buf,n); close(connfd); } return 0;}
clint
#include <stdio.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define MAXTIME 80#define PORT 6666int main(int argc ,char *argv[]){ struct sockaddr_in servaddr; char buf[MAXTIME]; int sockfd,n; char *str1,*str2; if(argc !=3){ fputs("please use :./clint message serveraddr\n",stderr); _exit(1); } str1=argv[1]; str2=argv[2]; sockfd =socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr ,sizeof(servaddr)); servaddr.sin_family =AF_INET; inet_pton(AF_INET, str2, &servaddr.sin_addr); servaddr.sin_port= htons(PORT); connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr)); write(sockfd,str1,strlen(str1)); n=read(sockfd,buf,MAXTIME); printf("Response from server:"); write(STDOUT_FILENO,buf,n); close(sockfd); return 0;}
高并发服务器
多进程并发服务器
使用多进程并发服务器时要考虑以下几点:
- 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
- 系统内创建进程个数(与内存大小相关)
- 进程创建过多是否降低整体服务性能(进程调度)
server_v1
#include <stdio.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <signal.h>#include <sys/wait.h>#include <sys/types.h>#include <unistd.h>#include <ctype.h>#define MAXLINE 80#define PORT 6666void do_sigchild(int num){ while(waitpid(0,NULL,WNOHANG));}int main(void){ struct sockaddr_in servaddr,cliaddr; socklen_t cliaddr_len; int listenfd,connfd; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; int i,n; pid_t pid; struct sigaction newact; newact.sa_handler= do_sigchild; sigemptyset(&newact.sa_mask); newact.sa_flags=0; sigaction(SIGCHLD,& newact,NULL); listenfd=socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family =AF_INET; servaddr.sin_addr.s_addr=htonl(INADDR_ANY); servaddr.sin_port=htons(PORT); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,20); printf("Accepting connections ...\n"); while(1){ cliaddr_len=sizeof(cliaddr); connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&cliaddr_len); //every time a clint come in ,I will fork a new pid pid =fork(); if(pid==0) { close(listenfd); while (1) { n=read(connfd,buf,MAXLINE); if(n==0){ printf("the clint is still closed.\n"); break; } printf("received from %s at port %d\n", inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)), ntohs(cliaddr.sin_port)); printf("%s\n",buf); for(i=0;i<n;i++)buf[i] =toupper(buf[i]); write(connfd,buf,n); } close(connfd); return 0; }else if(pid >0)close(connfd); else _exit(1); } close(listenfd); return 0;}
clint_v1
#include <stdio.h>#include <string.h>#include <netinet/in.h>#include <unistd.h>#include <arpa/inet.h>#define MAXLINE 80#define PORT 6666int main(int argc ,char *argv[]){ struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd ,n; char *str1; if(argc !=2){ fputs("please use :./clint message serveraddr\n",stderr); _exit(1); } str1=argv[1]; sockfd =socket(AF_INET,SOCK_STREAM,0); bzero(&servaddr,sizeof(servaddr)); servaddr.sin_family=AF_INET; inet_pton(AF_INET,str1,&servaddr.sin_addr); servaddr.sin_port=htons(PORT); connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); while(fgets(buf,MAXLINE,stdin)!=NULL){ write(sockfd,buf,strlen(buf)); n=read(sockfd,buf,MAXLINE); if(n==0) { printf("the other hide has been closed.\n"); break; }else { write(STDOUT_FILENO,buf,n); } } close(sockfd); return 0;}
多线程并发服务器
在使用线程模型开发服务器时需考虑以下问题:
- 调整进程内最大文件描述符上限
- 线程如有共享数据,考虑线程同步
- 服务于客户端线程退出时,退出处理。(退出值,分离态)
- 系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU
server_v2
/* server.c */#include <stdio.h>#include <string.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pthread.h>#include <ctype.h>#include <unistd.h>#define MAXLINE 80#define SERV_PORT 6666struct s_info { struct sockaddr_in cliaddr; int connfd;};void *do_work(void *arg){ int n,i; struct s_info *ts = (struct s_info*)arg; char buf[MAXLINE]; char str[INET_ADDRSTRLEN]; /* 可以在创建线程前设置线程创建属性,设为分离态,哪种效率高内? */ pthread_detach(pthread_self()); while (1) { n = read(ts->connfd, buf, MAXLINE); if (n == 0) { printf("the other side has been closed.\n"); break; } printf("received from %s at PORT %d\n", inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)), ntohs((*ts).cliaddr.sin_port)); printf("the message I receive :%s\n",buf); for (i = 0; i < n; i++) buf[i] = toupper(buf[i]); write(ts->connfd, buf, n); } close(ts->connfd);}int main(void){ struct sockaddr_in servaddr, cliaddr; socklen_t cliaddr_len; int listenfd, connfd; int i = 0; pthread_t tid; struct s_info ts[256]; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); listen(listenfd, 20); printf("Accepting connections ...\n"); while (1) { cliaddr_len = sizeof(cliaddr); connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); ts[i].cliaddr = cliaddr; ts[i].connfd = connfd; /* 达到线程最大数时,pthread_create出错处理, 增加服务器稳定性 */ pthread_create(&tid, NULL, do_work, (void*)&ts[i]); i++; } return 0;}
clint_v2
/* client.c */#include <stdio.h>#include <string.h>#include <unistd.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pthread.h>#include <ctype.h>#define MAXLINE 80#define SERV_PORT 6666int main(int argc, char *argv[]){ struct sockaddr_in servaddr; char buf[MAXLINE]; int sockfd, n; char* str; if(argc !=2){ fputs("please use :./clint serveraddr\n",stderr); _exit(1); } str=argv[1]; sockfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; inet_pton(AF_INET, str, &servaddr.sin_addr); servaddr.sin_port = htons(SERV_PORT); connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)); while (fgets(buf, MAXLINE, stdin) != NULL) { write(sockfd, buf, strlen(buf)); n = read(sockfd, buf, MAXLINE); if (n == 0) printf("the other side has been closed.\n"); else write(STDOUT_FILENO, buf, n); } close(sockfd); return 0;}
socket文件互传
sever_v3
#include <netinet/in.h> // sockaddr_in#include <sys/types.h> // socket#include <sys/socket.h> // socket#include <stdio.h> // printf#include <stdlib.h> // exit#include <string.h> // bzero#include <unistd.h>#include <arpa/inet.h>#include <pthread.h>#include <ctype.h>#define SERVER_PORT 8000#define LENGTH_OF_LISTEN_QUEUE 20#define BUFFER_SIZE 1024#define FILE_NAME_MAX_SIZE 512int main(void){ // 声明并初始化一个服务器端的socket地址结构 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = htons(INADDR_ANY); server_addr.sin_port = htons(SERVER_PORT); // 创建socket,若成功,返回socket描述符 int server_socket_fd = socket(PF_INET, SOCK_STREAM, 0); if(server_socket_fd < 0) { perror("Create Socket Failed:"); exit(1); } int opt = 1; setsockopt(server_socket_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); // 绑定socket和socket地址结构 if(-1 == (bind(server_socket_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)))) { perror("Server Bind Failed:"); exit(1); } // socket监听 if(-1 == (listen(server_socket_fd, LENGTH_OF_LISTEN_QUEUE))) { perror("Server Listen Failed:"); exit(1); } while(1) { // 定义客户端的socket地址结构 struct sockaddr_in client_addr; socklen_t client_addr_length = sizeof(client_addr); // 接受连接请求,返回一个新的socket(描述符),这个新socket用于同连接的客户端通信 // accept函数会把连接到的客户端信息写到client_addr中 int new_server_socket_fd = accept(server_socket_fd, (struct sockaddr*)&client_addr, &client_addr_length); if(new_server_socket_fd < 0) { perror("Server Accept Failed:"); break; } // recv函数接收数据到缓冲区buffer中 char buffer[BUFFER_SIZE]; bzero(buffer, BUFFER_SIZE); if(recv(new_server_socket_fd, buffer, BUFFER_SIZE, 0) < 0) { perror("Server Recieve Data Failed:"); break; } // 然后从buffer(缓冲区)拷贝到file_name中 char file_name[FILE_NAME_MAX_SIZE+1]; bzero(file_name, FILE_NAME_MAX_SIZE+1); strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer)); printf("%s\n", file_name); // 打开文件并读取文件数据 FILE *fp = fopen(file_name, "r"); if(NULL == fp) { printf("File:%s Not Found\n", file_name); } else { bzero(buffer, BUFFER_SIZE); int length = 0; // 每读取一段数据,便将其发送给客户端,循环直到文件读完为止 while((length = fread(buffer, sizeof(char), BUFFER_SIZE, fp)) > 0) { if(send(new_server_socket_fd, buffer, length, 0) < 0) { printf("Send File:%s Failed./n", file_name); break; } bzero(buffer, BUFFER_SIZE); } // 关闭文件 fclose(fp); printf("File:%s Transfer Successful!\n", file_name); } // 关闭与客户端的连接 close(new_server_socket_fd); } // 关闭监听用的socket close(server_socket_fd); return 0;}
clint_v3
#include <netinet/in.h> // sockaddr_in#include <sys/types.h> // socket#include <sys/socket.h> // socket#include <stdio.h> // printf#include <stdlib.h> // exit#include <string.h> // bzero#include <unistd.h>#include <arpa/inet.h>#include <pthread.h>#include <ctype.h>#include <opencv2/opencv.hpp>#define SERVER_PORT 8000#define BUFFER_SIZE 1024#define FILE_NAME_MAX_SIZE 512int main(int argc, char *argv[]){ // 声明并初始化一个客户端的socket地址结构 struct sockaddr_in client_addr; bzero(&client_addr, sizeof(client_addr)); client_addr.sin_family = AF_INET; client_addr.sin_addr.s_addr = htons(INADDR_ANY); client_addr.sin_port = htons(0); char* str; if(argc !=2){ fputs("please use :./clint serveraddr\n",stderr); exit(1); } str=argv[1]; // 创建socket,若成功,返回socket描述符 int client_socket_fd = socket(AF_INET, SOCK_STREAM, 0); if(client_socket_fd < 0) { perror("Create Socket Failed:"); exit(1); } // 绑定客户端的socket和客户端的socket地址结构 非必需 if(-1 == (bind(client_socket_fd, (struct sockaddr*)&client_addr, sizeof(client_addr)))) { perror("Client Bind Failed:"); exit(1); } // 声明一个服务器端的socket地址结构,并用服务器那边的IP地址及端口对其进行初始化,用于后面的连接 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; if(inet_pton(AF_INET, str, &server_addr.sin_addr) == 0) { perror("Server IP Address Error:"); exit(1); } server_addr.sin_port = htons(SERVER_PORT); socklen_t server_addr_length = sizeof(server_addr); // 向服务器发起连接,连接成功后client_socket_fd代表了客户端和服务器的一个socket连接 if(connect(client_socket_fd, (struct sockaddr*)&server_addr, server_addr_length) < 0) { perror("Can Not Connect To Server IP:"); exit(0); } // 输入文件名 并放到缓冲区buffer中等待发送 char file_name[FILE_NAME_MAX_SIZE+1]; bzero(file_name, FILE_NAME_MAX_SIZE+1); printf("Please Input File Name On Server:\t"); scanf("%s", file_name); char buffer[BUFFER_SIZE]; bzero(buffer, BUFFER_SIZE); strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name)); // 向服务器发送buffer中的数据 if(send(client_socket_fd, buffer, BUFFER_SIZE, 0) < 0) { perror("Send File Name Failed:"); exit(1); } // 打开文件,准备写入 FILE *fp = fopen(file_name, "w"); if(NULL == fp) { printf("File:\t%s Can Not Open To Write\n", file_name); exit(1); } // 从服务器接收数据到buffer中 // 每接收一段数据,便将其写入文件中,循环直到文件接收完并写完为止 bzero(buffer, BUFFER_SIZE); int length = 0; while((length = recv(client_socket_fd, buffer, BUFFER_SIZE, 0)) > 0) { if(fwrite(buffer, sizeof(char), length, fp) < length) { printf("File:\t%s Write Failed\n", file_name); break; } bzero(buffer, BUFFER_SIZE); } // 接收成功后,关闭文件,关闭socket printf("Receive File:\t%s From Server IP Successful!\n", file_name); fclose(fp); close(client_socket_fd); return 0;}
发表评论
最新留言
哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年03月24日 12时22分55秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
利用Python实现循环队列
2021-05-08
利用递归实现二叉树的前中后序遍历(Python)
2021-05-08
冒泡排序又来啦(C/C++版本)
2021-05-08
python负数存储
2021-05-08
求二维数组中最大值的位置
2021-05-08
python中sort和sorted的区别
2021-05-08
maven安装
2021-05-08
合并两个有序数组
2021-05-08
Ubuntu 环境下使用中文输入法
2021-05-08
聊聊我的五一小假期
2021-05-08
面向对象之异常处理:多路捕获
2021-05-08
Python简易五子棋
2021-05-08
Vue新建项目——页面初始化
2021-05-08
Cent OS 7.6 服务器软件安装(这篇博客主要是为了方便我配置云主机的)
2021-05-08
Node.js包使用系列(一)——修改NPM全局下载和缓存路径
2021-05-08
TDengine使用(一)——TDengine下载与安装
2021-05-08
6.14编一个程序,将两个字符串s1和s2比较,不要用strcmp函数。
2021-05-08
Java纯文本文件显示工具制作
2021-05-08
Unity2D Fixed Joint 2D详解
2021-05-08