套接字相关函数socket()、bind()、listen()、connect()、accept()、recv()、send()、select()、close()
https://blog.csdn.net/weixin_45525272/article/details/107732407
atoi
atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数,应用在计算机程序和办公软件中。int atoi(const char *nptr)
函数会扫描参数 nptr字符串,会跳过前面的空白字符(例如空格,tab缩进)等。如果 nptr不能转换成 int 或者 nptr为空字符串,那么将返回 0 。特别注意,该函数要求被转换的字符串是按十进制数理解的。atoi输入的字符串对应数字存在大小限制(与int类型大小有关),若其过大可能报错-1。
htons
htons是将整型变量从主机字节顺序转变成网络字节顺序, 就是整数在地址空间存储方式变为高位字节存放在内存的低地址处。
bzero()函数
原型:extern void bzero(void *s, int n
);
参数说明:s 要置零的数据的起始地址;
n 要置零的数据字节个数。
用法:#include <string.h>
功能:置字节字符串s的前n个字节为零且包括‘\0’。
说明:bzero无返回值,并且使用string.h头文件,string.h曾经是posix标准的一部分,但是在POSIX.1-2001标准里面,这些函数被标记为了遗留函数而不推荐使用。在POSIX.1-2008标准里已经没有这些函数了。推荐使用memset替代bzero。
/************************************************************************* > File Name: server_fork.c > Author: 杨永利 > Mail: 1795018360@qq.com > Created Time: 2020年08月01日 星期六 10时02分04秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <strings.h> int main(int argc, char* argv[]){ if (argc!=2) { /* code */ printf("参数错误!\n"); return -1; } // 第一步 创建套接字描述符 int server_socket=socket(PF_INET,SOCK_STREAM,0); //第二步 创建服务器地址结构 struct sockaddr_in server_addr; bzero(&server_addr, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(atoi(argv[1])); //INADDR_ANY就是指定地址为0.0.0.0的地址,这个地址事实上表示不确定地址,或“所有地址”、“任意地址”。 一般来说,在各个系统中均定义成为0值。 server_addr.sin_addr.s_addr = /*htonl()*/INADDR_ANY; // 第三步 绑定套接字 if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr))) { /* code */ printf("绑定套接字失败!\n"); return -1; } // 第四步 监听套接字 if (listen(server_socket,10)) { /* code */ printf("监听套接字失败!\n"); return -1; } // 第五步 多进程连接 struct sockaddr_in client_addr; int client_addr_size=sizeof(client_addr); while(1) { int client_socket=0; bzero(&client_addr,sizeof(client_addr)); if((client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_addr_size)) == -1) { printf("接收客户端失败!\n-----client_socket=%d",client_socket); return -1; } // 创建子进程 fork() /* 负值:创建子进程失败。 零:返回到新创建的子进程。 正值:返回父进程或调用者。该值包含新创建的子进程的进程ID */ int pid=fork(); // 创建新的子进程成功 if (pid==0) { // 创建临时客户端地址结构体用于存放开始accept到的客户端数据 struct sockaddr_in client_in_addr; client_in_addr.sin_addr.s_addr=client_addr.sin_addr.s_addr; client_in_addr.sin_port=client_addr.sin_port; printf("来了一个新的客户端,ip是:%s,端口:%d\n", inet_ntoa(client_addr.sin_addr),client_in_addr.sin_port); // 关闭当前进程的套接字描述符, close(server_socket); char buf[1024]; int recv_len; while(1) { bzero(buf, sizeof(buf)); if((recv_len = recv(client_socket, buf, sizeof(buf), 0)) < 0) return -1; // 判断如果接收到为0就有个客户端退出,跳出循环 if(!recv_len){ printf("有客户端退出了,ip:%s 端口:%d\n", inet_ntoa(client_in_addr.sin_addr),client_in_addr.sin_port);//struct in_addr break; } printf("客户端-%s -%d 对我说:%s\n",inet_ntoa(client_in_addr.sin_addr),client_in_addr.sin_port,buf); if(send(client_socket, buf, strlen(buf), 0) <= 0) return -1; } close(client_socket); return 0; } // 返回给父进程子进程id 父进程就可以关闭接收的套接字描述符 else if(pid > 0) { close(client_socket); } else //创建子进程失败,直接退出 exit(-1); } return 0; }
/************************************************************************* > File Name: client.c > Author: 杨永利 > Mail: 1795018360@qq.com > Created Time: 2020年08月01日 星期六 10时01分47秒 ************************************************************************/ #include <stdio.h> #include <unistd.h> #include <arpa/inet.h> #include <netinet/in.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <string.h> #include <strings.h> int main(int argc, char* argv[]){ if (argc != 3) { printf("参数错误!\n"); return -1; } // 第一步创建网络通信套接字描述符 int client_socket=socket(AF_INET,SOCK_STREAM,0); // 第二步创建服务器的地址结构体 struct sockaddr_in server_addr; bzero(&server_addr,sizeof(server_addr)); server_addr.sin_family=AF_INET; server_addr.sin_port=htons(atoi(argv[2])); server_addr.sin_addr.s_addr=inet_addr(argv[1]); // 第三步 连接服务器 if (connect(client_socket,(struct sockaddr*)&server_addr,sizeof(server_addr))==-1) { /* code */ printf("连接服务器失败!\n"); return -1; } printf("连接服务器成功!\n"); char message[1024]; bzero(message,sizeof(message)); char buf[1024]; printf("我是客户端,我将给服务器发送内容\n"); printf("如果希望聊天退出,请输入q或者Q:\n"); while(1) { printf("我发送给服务器的:\n"); scanf("%s",buf); if (strlen(buf)==1) { if(buf[0] == 'q' || buf[0] == 'Q') break; } if(strlen(buf) != write(client_socket, buf, strlen(buf))){ printf("write() error!\n"); exit(-1); } if(read(client_socket, message, sizeof(message)) <= 0){ printf("read() error!\n"); return -1; } printf("服务器对我说:%s\n", message); bzero(buf, sizeof(buf)); bzero(message, sizeof(message)); } close(client_socket); printf("服务器关闭了!\n"); return 0; }