当前位置: 首页 > news >正文

【Linux网络编程_TCP/UDP_字节序_套接字 实现: FTP 项目_局域网聊天项目 (已开源) 】.md updata:23/11/03

文章目录

      • TCP/UDP对比
      • 端口号作用
      • 字节序
      • 字节序转换api
      • 套接字 socket
        • 实现网络通讯服务端 逻辑思路
          • demo:
        • 满血版双方通讯/残血版多方通讯
          • 服务端 demo
          • 客户端 demo
        • FTP 项目实现
          • sever demo:
          • client demo:
        • 局域网多方通讯 配合线程实现
          • sever demo:
          • client demo:

TCP/UDP对比

  1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前 不需要建立连接
  2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
  3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
    UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
  4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
  5. TCP首部开销20字节;UDP的首部开销小,只有8个字节
  6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道

端口号作用

一台拥有IP地址的主机可以提供许多服务,比如Web服务、FTP服务、SMTP服务等

这些服务完全可以通过1个IP地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠IP地址,因为IP 地址与网络服务的关系是一对多的关系。

实际上是通过“IP地址+端口号”来区 分不同的服务的。
端口提供了一种访问通道,
服务器一般都是通过知名端口号来识别的。例如,对于每个TCP/IP实现来说,FTP服务器的TCP端口号都是21,每个Telnet服务器的TCP端口号都是23,每个TFTP(简单文件传送协议)服务器的UDP端口号都是69。

字节序

Little endian 小端字节序 -低位在前
Big endian 大端字节序 -高位在前
网络字节序 = 大端字节序 -高位在前

字节序转换api

#include <netinet/in.h>uint16_t htons(uint16_t host16bitvalue);    
//返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);    
//返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);     
//返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);     
//返回主机字节序的值h代表host,n代表net,s代表short(两个字节),
l代表long(4个字节),[据需求选择即可];
通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。
有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

套接字 socket

实现网络通讯服务端 逻辑思路
  1. 创建套接字 规定地址族议、TCP/UDP等协议;
  2. 绑定套接字到服务器ip+端口,ip+端口储存在struct sockaddr类型的结构体指针内,可以使用更好用的struct sockaddr_in结构体类型 转成struct sockaddr类型 即可;
  3. 服务器监听客户端接入;
  4. 接收客户端套接字 并选择是否接受信息;
  5. 根据客户端的套接字,进行 读/写;
demo:
// 可以使用linux 的 telnet 连接服务器ip,进行测试;
// 因为是测试demo,这里绑定的服务器ip需在代码内修改,
// 后续的双方通讯则在运行时代码时怎加后缀argv参数即可; 
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
int main()
{//int socket(int domain, int type, int protocol);//01 创建套接字,返回套接字ID;int s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd < 0){perror("socket error:");exit(-1);}
/*struct sockaddr_in 是一个用于存储 IPv4 地址和端口号的结构体,其原型定义如下:struct sockaddr_in {sa_family_t sin_family;     // 地址族,一般为 AF_INETin_port_t sin_port;         // 16 位 TCP/UDP 端口号,网络字节序struct in_addr sin_addr;    // 32 位 IPv4 地址,网络字节序? 原型struct in_addr {in_addr_t s_addr;    // 32 位 IPv4 地址,网络字节序};char sin_zero[8];           // 未使用,填充 0};在网络编程中,可以使用 struct sockaddr_in 结构体来表示套接字的地址信息,例如在客户端与服务器之间建立 TCP 连接时,需要指定服务器的 IP 地址和端口号,可以将这些信息存储在一个 struct sockaddr_in 类型的结构体中,并传递给 connect() 函数或者 bind() 函数。需要注意的是,在使用 struct sockaddr_in 结构体时,需要将其中的端口号和 IP 地址转换为网络字节序(big-endian),可以使用 htons() 函数和 inet_aton() 函数来进行转换。同时,在使用 struct sockaddr_in 结构体时,也需要注意其大小和对齐方式,以确保在不同的系统上都能正确地解析套接字地址信息。
*/struct sockaddr_in s_addr;s_addr.sin_family = AF_INET;s_addr.sin_port = htons(8989);//int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton("192.168.1.211",&s_addr.sin_addr);//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//int listen(int sockfd, int backlog);//03 监听,最多听几次,这里是10次listen(s_fd,10);//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//04 在服务端套接字,接收客户端地址信息,并创建一个新的套接字来处理这些信息;//这里不在乎客户端的信息,直接NULL,拿了新的套接字空间len也NULL;int c_fd = accept(s_fd,NULL,NULL);//05 read//06 writeprintf("new one connect!\n");while(1);return 0;
}
满血版双方通讯/残血版多方通讯

满血双方通讯:服务器与客户端 流畅沟通
残血版多方通讯:多运行几个客户端,多个客户端争抢服务端的消息,谁抢到谁显示;
(解决思路:
1.有几个客户端接入,就mark++,根据mark的数量,创建线程给每个客户端发消息;
2.
)

服务端 demo

#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main(int argc,char** argv)
{if(argc < 3){printf("please input two argv : ip and port\n");}//int socket(int domain, int type, int protocol);//01 创建套接字,返回套接字ID;int s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd < 0){perror("socket error:");exit(-1);}struct sockaddr_in c_addr;struct sockaddr_in s_addr;s_addr.sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序s_addr.sin_port = htons(atoi(argv[2]));//int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&s_addr.sin_addr);//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//int listen(int sockfd, int backlog);//03 监听,最多听几次,这里是10次listen(s_fd,100);int mark =0;while(1){//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//04 在服务端套接字,接收客户端地址信息,并创建一个新的套接字来处理这些信息;//如不在乎客户端的信息,直接NULL,拿了新的套接字空间len也NULL;int nsize = sizeof(struct sockaddr_in);int c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&nsize);if(c_fd < 0){perror("accept client error");}else{mark++;}//inet_ntoa() 把网络字节序转成int;printf("new connect:%s \n",inet_ntoa(c_addr.sin_addr));//06 writeif(fork() == 0){ if(fork() == 0){                    //06 writewhile(1){char dataStr[1024*5] = {0};                        gets(dataStr);int n_write = write(c_fd,dataStr,strlen(dataStr)+1); }  }                //05 readchar buf[1024] = {0};char buf1[1024] = {0};while(1){int n_read = read(c_fd,buf,1024);if(strcmp(buf,buf1) != 0){printf("client massage:no.%d -- %s\n",n_read,buf); memset(buf1,0,1024);strcpy(buf1,buf);memset(buf,0,1024);}}} }return 0;}
客户端 demo
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main(int argc,char** argv)
{if(argc < 3){printf("please input two argv : ip and port\n");}//int socket(int domain, int type, int protocol);//01 创建套接字,返回套接字ID;int c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd < 0){perror("socket error:");exit(-1);}struct sockaddr_in c_addr;c_addr.sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序c_addr.sin_port = htons(atoi(argv[2]));//int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&c_addr.sin_addr);//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 客户端连接服务器的ip和端口;connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));//inet_ntoa() 把网络字节序转成int;printf("connect sever:%s \n",inet_ntoa(c_addr.sin_addr)); while(1){         if(fork() == 0){                    //06 writewhile(1){char dataStr[1024*5] = {0};                        gets(dataStr);int n_write = write(c_fd,dataStr,strlen(dataStr)+1); }}                //05 readchar buf[1024] = {0};char buf1[1024] = {0};while(1){int n_read = read(c_fd,buf,1024);if(strcmp(buf,buf1) != 0){printf("server massage:%s  (size:%d)\n",buf,n_read); memset(buf1,0,1024);strcpy(buf1,buf);memset(buf,0,1024);}}                 }return 0;
}
FTP 项目实现

功能:get put ls pwd cd lls lpwd

sever demo:
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LS      0
#define GET     1
#define PWD     2
#define LPWD    3
#define LCD     4
#define LLS     5
#define CD      6
#define PUT     7
#define QUIT    8
#define DOFILE  9
struct sockaddr_in c_addr;
struct sockaddr_in s_addr;struct MASSAGE 
{int type;char data[1024*5];char secondBuf[128];
}Msg;char* getdir(char* comdata)
{char* a = strtok(comdata, " ");if (a == NULL) {return NULL;}char* b = strtok(NULL, " ");if (b == NULL) {return a;  // 如果没有空格,直接返回第一个字符串} else {return b;  // 如果有空格,返回第二个字符串}
}int getNCOM(char* comdata) 
{if (strcmp(comdata, "ls") == 0)         return 0;if (strncmp(comdata, "get", 3) == 0)    return 1;if (strcmp(comdata, "pwd") == 0)        return 2;if (strcmp(comdata, "lpwd") == 0)       return 3;if (strncmp(comdata, "lcd", 3) == 0)    return 4;if (strcmp(comdata, "lls") == 0)        return 5;if (strncmp(comdata, "cd", 2) == 0)     return 6;if (strncmp(comdata, "put", 3) == 0)    return 7;if (strcmp(comdata, "quit") == 0)       return 8;if (strncmp(comdata, "dofile", 6) == 0) return 9;/* 提示命令不存在 错误 */               return 10; 
}void doCom(char* comdata,int c_fd)
{char dir[1024] = {0};//获取空格后的部分命令,没有空格则返回原命令strcpy(dir,getdir(comdata));if(*dir == 0){perror("why");}    //将命令转成int宏;int nCom = getNCOM(comdata);int op_fd = 0;//定义一个1个文件流指针放popen的文件流;FILE * r;char dir1[1024*2] = {0};char dir2[1024*2] = {0};switch(nCom){case LS :case PWD:r = popen(dir,"r");fread(dir1,sizeof(dir1),1,r);write(c_fd,dir1,sizeof(dir1));break;case CD:  if(strcmp("cd",dir) >= 0){chdir("/");                } else if(chdir(dir) < 0){perror("chdir 路径切换失败!");}break;case GET:sprintf(dir1,"./%s",dir);printf("file path:%s\n",dir1);op_fd = open(dir1,O_RDWR,0666);if(op_fd < 0){perror("open error"); write(c_fd,"open error",100);   break;            }read(op_fd,dir1,sizeof(dir1));write(c_fd,dir1,strlen(dir1));close(op_fd);break;case PUT:sleep(1);sprintf(dir1,"./%s",dir);op_fd = open(dir1,O_RDWR|O_CREAT|O_TRUNC,0666);printf("dir1:%s\n",dir1);if(op_fd < 0){perror("open error");}       //memset(dir1,0,sizeof(dir1));if((recv(c_fd, dir2, sizeof(dir2), 0)) <= 0){perror("recv error");} printf("--:\n%s\n",dir2);write(op_fd,dir2,strlen(dir2));close(op_fd);break;case 10:sprintf(dir1,"error : commomd never!\n"); write(c_fd,dir1,sizeof(dir1));break;   }memset(dir,0,sizeof(dir));
} void initNetSocket(int argc,int* s_fd,char** argv)
{//判断main函数-参数数量if(argc < 3){printf("please input two argv!!\n");}//01 创建套接字,返回套接字ID;*s_fd = socket(AF_INET,SOCK_STREAM,0);if(*s_fd < 0){perror("socket error:");exit(-1);}   //设为IPV4 即AF_INET;s_addr.sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序s_addr.sin_port = htons(atoi(argv[2]));    //这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&s_addr.sin_addr);//把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;bind(*s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//int listen(int sockfd, int backlog);//监听,最多听几次,这里是10次,最多连10个客户端listen(*s_fd,10);       
}int main(int argc,char** argv)
{    int c_fd = 0;  int s_fd = 0;int nsize = sizeof(struct sockaddr_in);//初始化套接字,绑定服务端ip;检测main参数,设置监听最大数量;initNetSocket(argc,&s_fd,argv);while(1){//接收客户端连接c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&nsize);if(c_fd < 0){perror("accept client error");break;}// 显示新客户端连接,inet_ntoa() 把网络字节序转成int;printf("new connect:%s \n",inet_ntoa(c_addr.sin_addr));        if(fork() == 0){ //readwhile(1){                memset(Msg.data,0,sizeof(Msg.data));int n_read = read(c_fd,Msg.data,sizeof(Msg.data));if(n_read == 0){printf("client out!\n");break;}else if(n_read > 0){printf("client data:%s\n",Msg.data);doCom(Msg.data,c_fd);                      }    }}      }close(c_fd);  close(s_fd);  return 0;
}
client demo:
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LS      0
#define GET     1
#define PWD     2
#define LPWD    3
#define LCD     4
#define LLS     5
#define CD      6
#define PUT     7
#define QUIT    8
#define DOFILE  9char* getdir(char* comdata)
{char* a = strtok(comdata, " ");if (a == NULL) {return NULL;}char* b = strtok(NULL, " ");if (b == NULL) {return a;  // 如果没有空格,直接返回第一个字符串} else {return b;  // 如果有空格,返回第二个字符串}
}int getNCOM(char* comdata) 
{if (strcmp(comdata, "ls") == 0)         return 0;if (strncmp(comdata, "get", 3) == 0)    return 1;if (strcmp(comdata, "pwd") == 0)        return 2;if (strcmp(comdata, "lpwd") == 0)       return 3;if (strncmp(comdata, "lcd", 3) == 0)    return 4;if (strcmp(comdata, "lls") == 0)        return 5;if (strncmp(comdata, "cd", 2) == 0)     return 6;if (strncmp(comdata, "put", 3) == 0)    return 7;if (strcmp(comdata, "quit") == 0)       return 8;if (strncmp(comdata, "dofile", 6) == 0) return 9;/* 提示命令不存在 错误 */               return 10; 
}void doCom(char* comdata,int c_fd,int* fd)
{char dir[1024] = {0};    strcpy(dir,getdir(comdata));if(*dir == 0){perror("why");}int op_fd = 0;int nCom = getNCOM(comdata);FILE * r;char dir1[1024*2] = {0};switch(nCom){case LPWD:r = popen("pwd","r");fread(dir1,sizeof(dir1),1,r);printf("---------------------\n");printf("%s",dir1); printf("---------------------\n");break;case LLS:r = popen("ls","r");fread(dir1,sizeof(dir1),1,r);printf("---------------------\n");printf("%s",dir1); printf("---------------------\n");break;case GET:sprintf(dir1,"./%s",dir);op_fd = open(dir1,O_RDWR|O_CREAT|O_TRUNC,0666);  printf("creat file:%s\n",dir1);          if(op_fd < 0){perror("open error");break;}  //memset(dir1,0,sizeof(dir1));lseek(c_fd,0,SEEK_SET);if(read (c_fd,dir1,sizeof(dir1)) <= 0){perror("read why");}; printf("file data:\n%s\n",dir1);write(op_fd,dir1,strlen(dir1));close(op_fd);break;case PUT:sprintf(dir1,"./%s",dir);printf("dir1:%s\n",dir1);   op_fd = open(dir1,O_RDWR,0666);            if(op_fd < 0){perror("open error");}memset(dir1,0,sizeof(dir1));read(op_fd,dir1,sizeof(dir1)); printf("--:\n%s\n",dir1);       if(send(c_fd,dir1,sizeof(dir1),0) < 0){perror("send error");}   close(op_fd); break;case QUIT:printf("---------------------\n");printf("client quit!\n"); printf("---------------------\n");//如果pipe无名管道写入失败就提示;close(fd[0]);if (write(fd[1], "QU", 3) == -1) {perror("Failed to write to pipe");}close(fd[1]);break;   }memset(dir,0,sizeof(dir));
} 
void readx(int c_fd)
{char buf[1024*2] = {0};while(1){lseek(c_fd,0,SEEK_SET);int n_read = read(c_fd,buf,sizeof(buf));     if(n_read <= 0){printf("read:%d\n",n_read);exit(1);}printf("---------------------\n");printf("%s",buf); printf("---------------------\n");memset(buf,0,sizeof(buf));      }
}int checkQuit(int* fd)
{char data1[128] = {0};        close(fd[1]);read(fd[0],data1,128);if(strcmp("QU",data1) == 0){memset(data1,0,sizeof(data1));return 1;     } else{return 0;}
}void checkArgv(int argc)
{if(argc < 3){printf("please input two argv : ip and port\n");}
}void initNetSocket(struct sockaddr_in* c_addr,char** argv,int c_fd)
{c_addr->sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序c_addr->sin_port = htons(atoi(argv[2]));    //int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&c_addr->sin_addr);//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 客户端连接服务器的ip和端口--在c_addr结构体里配置;connect(c_fd,(struct sockaddr *)c_addr,sizeof(struct sockaddr_in));//显示要连接的服务器 ip//inet_ntoa() 把网络字节序转成int;printf("connect sever:%s \n",inet_ntoa(c_addr->sin_addr));
}void checkSocket(int c_fd)
{if(c_fd < 0){perror("socket error");}
}void initClientSocket(int argc,int* c_fd,char **argv)
{//检测此程序参数数量checkArgv(argc);//创建套接字,返回套接字ID;*c_fd = socket(AF_INET,SOCK_STREAM,0);//检测套接字创建checkSocket(*c_fd); //定义储存服务器ip和端口的结构体;struct sockaddr_in c_addr; //通过套接字,初始化连接,并显示结构体内要连接的服务器ip;initNetSocket(&c_addr,argv,*c_fd);
} int main(int argc,char** argv)
{   int c_fd;//init客户端 连接服务端ip;检测main参数,打印当前输入的服务器ip;initClientSocket(argc,&c_fd,argv);while(1){ //创建管道检测 quit 执行退出父进程;int fd[2];int n_pipe = pipe(fd); if(n_pipe < 0){printf("error: can not creat pipe!\n");perror("why");} //创建子进程;               if(fork() == 0){  if(fork() == 0){//循环读服务器执行命令的内容readx(c_fd);}//06 writewhile(1){char dataStr[1024*5] = {0};                                       gets(dataStr);int n_write = write(c_fd,dataStr,strlen(dataStr)+1);                doCom(dataStr,c_fd,fd);                }}  printf("open Q check -----\n"); //检测quit,一旦无名管道的fd[0]有"QU",就结束父进程;if(checkQuit(fd)){                break;}}return 0;
}
局域网多方通讯 配合线程实现

进程开辟多 容易崩亏,所以能用线程就用线程;

sever demo:
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
//创建客户端套接字数组
int c_fd[10] = {0};
//创建线程数组;
pthread_t t1[10];
//read用的字符串变量
char buf[1024] = {0};
char buf1[1024] = {0};
int mark = 0;
int count = 0;void *func2(void* marknum)
{int num2 = *((int*)marknum);printf("marknum:%d\n",num2);    //06 writewhile(1){char dataStr[1024*5] = {0};                        fgets(dataStr, sizeof(dataStr), stdin);        printf("now have :%d\n-----------------\n",count);for(int i = 0; i < count; i++){write(c_fd[i],dataStr,strlen(dataStr)+1);}}      
}
void *func1(void* marknum)
{int num = *((int*)marknum);pthread_create(&t1[*((int*)marknum)+1],NULL,func2,marknum);                //05 readwhile(1){int n_read = read(c_fd[num],buf,1024);if (n_read == 0) {// 客户端关闭连接,清空c_fd数组相应位置close(c_fd[num]);c_fd[num] = 0;printf("client %d closed\n", num);pthread_cancel(t1[num]); // 结束相应线程break;}if(strcmp(buf,buf1) != 0){printf("client massage --no.%d: %s\n",num,buf); memset(buf1,0,1024);strcpy(buf1,buf);memset(buf,0,1024);}}
}int main(int argc,char** argv)
{if(argc < 3){printf("please input two argv : ip and port\n");}//int socket(int domain, int type, int protocol);//01 创建套接字,返回套接字ID;int s_fd = socket(AF_INET,SOCK_STREAM,0);if(s_fd < 0){perror("socket error:");exit(-1);}struct sockaddr_in c_addr;struct sockaddr_in s_addr;s_addr.sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序s_addr.sin_port = htons(atoi(argv[2]));    //int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&s_addr.sin_addr);//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//int listen(int sockfd, int backlog);//03 监听,最多听几次,这里是10次listen(s_fd,10);    while(1){//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//04 在服务端套接字,接收客户端地址信息,并创建一个新的套接字来处理这些信息;//如不在乎客户端的信息,直接NULL,拿了新的套接字空间len也NULL;int nsize = sizeof(struct sockaddr_in);c_fd[count] = accept(s_fd,(struct sockaddr *)&c_addr,&nsize);if(c_fd < 0){perror("accept client error");}else{count++;mark++;}int marknum = mark-1;printf("****mark:%d\n",marknum);//inet_ntoa() 把网络字节序转成int;printf("new connect:%s \n",inet_ntoa(c_addr.sin_addr));pthread_create(&t1[marknum],NULL,func1, (void*)&marknum); // if(fork() == 0){//     func1((void*)&marknum);// }}   return 0;}
client demo:
#include <sys/types.h>      
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>int main(int argc,char** argv)
{if(argc < 3){printf("please input two argv : ip and port\n");}//int socket(int domain, int type, int protocol);//01 创建套接字,返回套接字ID;int c_fd = socket(AF_INET,SOCK_STREAM,0);if(c_fd < 0){perror("socket error:");exit(-1);}struct sockaddr_in c_addr;c_addr.sin_family = AF_INET;//htons(8989) 把数字转成网络字节序 即大端字节序c_addr.sin_port = htons(atoi(argv[2]));    //int inet_aton(const char *cp, struct in_addr *inp);//这里的ip是服务器本机的地址 ifconfig查看即可inet_aton(argv[1],&c_addr.sin_addr);//int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 把结构体addr里的 tcp+ip+端口,与套接字绑定在一起;//int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);//02 客户端连接服务器的ip和端口;connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr_in));//inet_ntoa() 把网络字节序转成int;printf("connect sever:%s \n",inet_ntoa(c_addr.sin_addr)); while(1){if(fork() == 0){                    //06 writewhile(1){char dataStr[1024*5] = {0};                        gets(dataStr);int n_write = write(c_fd,dataStr,strlen(dataStr)+1); }}                //05 readchar buf[1024] = {0};char buf1[1024] = {0};while(1){int n_read = read(c_fd,buf,1024);if(strcmp(buf,buf1) != 0){printf("server massage:%s  (size:%d)\n",buf,n_read); memset(buf1,0,1024);strcpy(buf1,buf);memset(buf,0,1024);}}                 }return 0;
}

相关文章:

【Linux网络编程_TCP/UDP_字节序_套接字 实现: FTP 项目_局域网聊天项目 (已开源) 】.md updata:23/11/03

文章目录 TCP/UDP对比端口号作用字节序字节序转换api套接字 socket实现网络通讯服务端 逻辑思路demo&#xff1a; 满血版双方通讯/残血版多方通讯服务端 demo客户端 demo FTP 项目实现sever demo:client demo: 局域网多方通讯 配合线程实现sever demo:client demo: TCP/UDP对比…...

Leetcode刷题详解——全排列

1. 题目链接&#xff1a;46. 全排列 2. 题目描述&#xff1a; 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],…...

JSONP 跨域访问(1), 简介, 原理, 实验, 缺点

JSONP 跨域访问(1), 简介, 原理, 实验, 缺点 一, JSONP 简介 JSONP&#xff08;JSON with Padding&#xff09;是一种非官方跨域数据交互协议。它允许web页面从不同的域名下加载数据。 由于同源策略&#xff0c;web页面通过XMLHttpRequest调用通常只允许访问与其自身相同域名…...

velero备份k8s集群

流程图 velero备份原理 本地 Velero 客户端发送备份指令。Kubernetes 集群内就会创建一个 Backup 对象。BackupController 监测 Backup 对象并开始备份过程。BackupController 会向 API Server 查询相关数据。BackupController 将查询到的数据备份到远端的对象存储。 velero的…...

描述低轨星座的特点和通信挑战,以及它们在5G和B5G中的作用。

文章目录 2章4 章5章&#xff08;没看&#xff09;6章&#xff08;没看&#xff09; 2章 将卫星星座中每个物理链路中可实现的数据速率、传播延迟和多普勒频移与3GPP技术报告中的参数进行分析和比较[3]。 相关配置 面向连接的网络&#xff0c;预先简历链路 卫星和地面终端有…...

Spring Boot实践 --windows环境下 K8s 部署 Docker

第一步&#xff1a;搭建项目并制作合适的jar包 这里我们准备好前面项目 用户管理系统 项目里的jar包。测试功能&#xff0c;定时任务会每过10s打印一次日志&#xff1a; E:\test>java -jar demospringboot-0.0.1-SNAPSHOT.jar2023-11-01 20:24:21.059 INFO 11848 --- [ …...

Linux 将Qt程序打包为AppImage包

前言 在 Linux 环境下&#xff0c;开发完 Qt 程序后&#xff0c;也需要制作为一个安装包或者可执行文件进行分发。这里介绍使用 linuxdeployqt 将 Qt 程序打包为 .AppImage 应用程序&#xff08;类似于 Windows 的绿色免安装软件&#xff09; 环境配置 配置 Qt 环境变量 这…...

修复国产电脑麒麟系统开机出现initramfs 问题

目录预览 一、问题描述二、原因分析三、解决方案四、知识点呀initramfsBusyBox 五、参考链接 一、问题描述 国产麒麟系统出现 initramfs 模式 二、原因分析 一般在拷贝卡顿过程【强制关机】或者电【脑异常断电】的情况下概率性导致系统分区损坏&#xff0c;重启后大概率就会进…...

机器人控制算法—如何使用C++读取pgm格式的栅格地图并转化为ROS地图格式的data?

1.Introduction 近期正在做全局规划局部动态规划的项目&#xff0c;目前遇到的问题是&#xff0c;我们如何利用C处理pgm地图文件。即将地图信息要与像素点结合起来。所以我们需要知道地图读取和处理的底层原理&#xff0c;这样更好地在非ROS平台下移植。 2.Main 如下几条信息…...

牛客项目(五)-使用kafka实现发送系统通知

kafka入门以及与spring整合 Message.java import java.util.Date;public class Message {private int id;private int fromId;private int toId;private String conversationId;private String content;private int status;private Date createTime;public int getId() {retur…...

计算机网络——第一章时延部分深入学习、相关习题及详细解析

目录 时延相关 习题1 习题1-改 习题2 时延相关 之前我们学习过&#xff0c;时延由发送时延、传播时延和处理时延三部分构成。 发送时延的计算公式为“分组长度除以发送速率”&#xff0c; 发送速率应该从网卡速率、信道带宽、以及对端的接口速率中取最小。 传播时延的计…...

CSS3媒体查询与页面自适应

2017年9月&#xff0c;W3C发布媒体查询(Media Query Level 4)候选推荐标准规范&#xff0c;它扩展了已经发布的媒体查询的功能。该规范用于CSS的media规则&#xff0c;可以为文档设定特定条件的样式&#xff0c;也可以用于HTML、JavaScript等语言。 1、媒体查询基础 媒体查询…...

UG\NX二次开发 超长的对象属性值,怎么设置

文章作者:里海 来源网站:里海NX二次开发3000例专栏 感谢粉丝订阅 感谢 Dr. Lin 订阅本专栏,非常感谢。 简介 使用UF_ATTR_assign设置对象属性,如果属性值超过UF_ATTR_MAX_STRING_LEN则会报错。 #define UF_ATTR_MAX_STRING_LEN 132 怎么办呢?下面这种方法可以解决: 效果 …...

流媒体服务实现H5实时预览视频

目录 背景方案业务实践细节注意 待办 背景 客户aws服务磁盘存储告急&#xff0c;最高可扩容16T。排查如下&#xff1a;主要是视频文件存在大量复制使用的情况。例如发布节目时复制、预览时复制&#xff0c;这样上传一份视频后最大会有四份拷贝&#xff08;预览、普通发布、互动…...

C++适配器

文章目录 引言栈和队列 priority_queue仿函数迭代器区间 引言 栈的特性是先进后出&#xff0c;队列的特性是先进先出&#xff0c;然而双向队列同时具有栈和队列的特性&#xff0c;所以我们可以通过双向队列来适配出栈和队列。 先看库里面 栈和队列 stack和queue模板参数里面都…...

基于openresty waf二次开发多次匹配到的ip再做拉黑

我们想在openresty waf的基础上做二次开发&#xff0c;比如再精确一些。比如我们先匹配到了select的url我们先打分10分&#xff0c;匹配到cc 1000/s我们再给这个ip打10分…直到100分我们就拉黑这个ip。 [openresty waf][1] #cat reids_w.lua require lib local redis require…...

新一代构建工具Vite-xyphf

一、什么vite? vite:是一款思维比较前卫而且先进的构建工具,他解决了一些webpack解决不了的问题——在开发环境下可以实现按需编译&#xff0c;加快了开发速度。而在生产环境下&#xff0c;它使用Rollup进行打包&#xff0c;提供更好的tree-shaking、代码压缩和性能优化&…...

Flink源码解析三之执行计划⽣成

JobManager Leader 选举 首先flink会依据配置获取RecoveryMode,RecoveryMode一共两两种:STANDALONE和ZOOKEEPER。 如果用户配置的是STANDALONE,会直接去配置中获取JobManager的地址如果用户配置的是ZOOKEEPER,flink会首先尝试连接zookeeper,利用zookeeper的leadder选举服务发现…...

Flutter 常见错误记录总结

1、当 flutter pub get 指令报如下错误时&#xff1a; pub get failed command: "/Users/***/developer/flutter/bin/cache/dart-sdk/bin/dart __deprecated_pub --color --directory . get --example" pub env: { "FLUTTER_ROOT": "/Users/***/dev…...

[ASP]校无忧在线报名系统 v2.1

校无忧在线报名系统为了满足各地不同的报名人员的需求&#xff0c;为提供更为高效、方便、快捷的报名条件&#xff0c;同时也为减轻管理人员的工作难度&#xff1b;更为协调报名人员与管理人员的关系&#xff0c;快速提高了报名人员与管理人员的工作效率应运而生。系统适用于政…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

C++实现分布式网络通信框架RPC(3)--rpc调用端

目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中&#xff0c;我们已经大致实现了rpc服务端的各项功能代…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

自然语言处理——Transformer

自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效&#xff0c;它能挖掘数据中的时序信息以及语义信息&#xff0c;但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN&#xff0c;但是…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

优选算法第十二讲:队列 + 宽搜 优先级队列

优选算法第十二讲&#xff1a;队列 宽搜 && 优先级队列 1.N叉树的层序遍历2.二叉树的锯齿型层序遍历3.二叉树最大宽度4.在每个树行中找最大值5.优先级队列 -- 最后一块石头的重量6.数据流中的第K大元素7.前K个高频单词8.数据流的中位数 1.N叉树的层序遍历 2.二叉树的锯…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合

在汽车智能化的汹涌浪潮中&#xff0c;车辆不再仅仅是传统的交通工具&#xff0c;而是逐步演变为高度智能的移动终端。这一转变的核心支撑&#xff0c;来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒&#xff08;T-Box&#xff09;方案&#xff1a;NXP S32K146 与…...