【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;}

高并发服务器

在这里插入图片描述多进程并发服务器
使用多进程并发服务器时要考虑以下几点:

  1. 父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)
  2. 系统内创建进程个数(与内存大小相关)
  3. 进程创建过多是否降低整体服务性能(进程调度)

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;}

多线程并发服务器

在使用线程模型开发服务器时需考虑以下问题:

  1. 调整进程内最大文件描述符上限
  2. 线程如有共享数据,考虑线程同步
  3. 服务于客户端线程退出时,退出处理。(退出值,分离态)
  4. 系统负载,随着链接客户端增加,导致其它线程不能及时得到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;}
上一篇:ubuntu16.04 配置中文输入
下一篇:【LINUX网络编程】LINUX Socket编程基础

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2025年03月24日 12时22分55秒