套接字相关函数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;
}