1. 进行头文件的编写
将server.c中的socket函数和client.c中的socket函数封装进去头文件,这样就可以直接在服务端或客户端直接进行调用,不需要每次都编写socket函数。
1.1 对server.c进行修改。
原代码可参照上一篇笔记——Linux学习-通信-Socket编写
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
//头文件不发生改变。
int socketServerCreate(char *ip,char *port) //自定义函数名,这里传参由main函数传
{
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof( struct sockaddr_in));
//1.socket
int s_fd;
s_fd=socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1)
{
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(atoi(port));
inet_aton(ip,&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
return s_fd;
}
//做到listen()函数即可
1.2. 对Client.c进行修改。
原代码可参照上一篇笔记——Linux学习-通信-Socket编写
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
int socketClientCreate(char*ip,char *port)//自定义函数名,这里传参由main函数传
{
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof( struct sockaddr_in));
//1.socket
int c_fd;
c_fd=socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1)
{
perror("socket");
exit(-1);
}
c_addr.sin_family=AF_INET;
c_addr.sin_port=htons(atoi(port));
inet_aton(ip,&c_addr.sin_addr);
//2.connect
int c_connect=connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr));
if(c_connect==-1)
{
perror("connect");
exit(-1);
}
return c_fd;//返回客户端通信的标识符。
}
1.3 将server.c和client.c合并写自己的封装函数
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
//服务端部分
int socketServerCreate(char *ip,char *port)
{
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof( struct sockaddr_in));
//1.socket
int s_fd;
s_fd=socket(AF_INET,SOCK_STREAM,0);
if(s_fd==-1)
{
perror("socket");
exit(-1);
}
s_addr.sin_family=AF_INET;
s_addr.sin_port=htons(atoi(port));
inet_aton(ip,&s_addr.sin_addr);
//2.bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3.listen
listen(s_fd,10);
return s_fd;
}
//客户端部分
int socketClientCreate(char*ip,char *port)
{
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof( struct sockaddr_in));
//1.socket
int c_fd;
c_fd=socket(AF_INET,SOCK_STREAM,0);
if(c_fd==-1)
{
perror("socket");
exit(-1);
}
c_addr.sin_family=AF_INET;
c_addr.sin_port=htons(atoi(port));
inet_aton(ip,&c_addr.sin_addr);
//2.connect
int c_connect=connect(c_fd,(struct sockaddr *)&c_addr,sizeof(struct sockaddr));
if(c_connect==-1)
{
perror("connect");
exit(-1);
}
return c_fd;
}
自定义封装函数名,我这里用的是mySocketAPI.c
1.4 编写头文件
头文件仅需要mySocketAPI.c中的头部分和声明部分即可。
#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
//#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
int socketServerCreate(char *ip,char *port);//记得加分号
int socketClinentCreate(char*ip,char *port);
自定义头函数名,我这里用的是mySocketAPI.h
1.5总结
经过以上4个步骤,头文件已经成功地写好,后面编写server.c和client.c时,只需要调用头文件中的socketSocketCreate()和socketClinentCreate()即可。
2.两端代码编写以及编译
2.1server.c的编写
#include<stdio.h>
#include"mySocketAPI.h"//这里用“”而不用<>的原因,下文会解释
int main(char *argc,char **argv)
{
int s_fd;
int c_fd;
char buf[32] = {};
s_fd = socketServerCreate(argv[1],argv[2]);//仅用一行代码调用头文件中的函数。
while(1){
c_fd = accept(s_fd,NULL,NULL);
read(c_fd,buf,32);
printf("get msg:%s\n",buf);
}
return 0;
}
2.2client.c的编写
#include<stdio.h>
#include"mySocketAPI.h"
int main(char *argc,char **argv)
{
int c_fd;
char *msg = "hello,this is client!";
c_fd = socketClientCreate(argv[1],argv[2]);
if(c_fd != -1){
write(c_fd,msg,strlen(msg));
}
return 0;
}
2.3 两端代码的编译
如果代码中用的<>写头文件,如下图:
会提示找不到头文件,如图:
原因: 编译器在编译时候会默认从 /user / include / 文件夹下面去找头文件。而我们自己封装的头文件不在此目录。这里有两种解决办法。
方法①:将声明头文件中的 <> 改为 “” 即可。如图:
改为引号之后,编译器编译时就会从当前目录寻找这个头文件。
找不到时候再去 /user / include / 寻找。
再次编译时候会出现这个问题。如图:
提示找不到socketServerCreate这个函数,这里需要将socket.c和mySocketAPI.c一起编译即可。
方法②: 不改变声明头文件中的 <> 。
在编译时候知名头文件的位置。这里用 -I 来知名头文件地址,如图:
解决编译问题后,将客户端端代码也编译。如图;
3. 运行两端代码
运行服务端代码:
运行客户端代码:
服务端接收到信息: