Linux下的基本网络编程(基于socket套接字)
Linux下的基本编程方法
作为网络编程的新手,我对此也不是特别熟练,仅仅基于书本以及自己完成的实验用简单的说明加以讲解,帮助入手linux下网络编程的人更快的了解这种思想。
过段时间我会继续更新windows下的编程方法
如有错误希望指正,谢谢。
socket()函数
在讲述函数前希望对于socket套接字有一定的印象。
socket在英文中的含义为插座。
作为计算机与网络通信的的媒介,socket的学习是网络编程的基础。
通过在套接字绑定目的IP以及端口号,实现与服务器等其它设备的服务请求。
socket(int family,int type,int protocal)
函数的作用为创建一个新的网络套接字,返回值为int。
当返回值大于0时,套接字创建成功,失败时则返回-1;
参数列表:
int family 协议簇 :一般只有两种 AF_INET ,AF_UNIX.
在C/S模式下均使用AF_INET。
AF_UNIX作为UNIX域套接字使用。
int type 数据的类型:SOCK_STREAM 流式套接字 以及SOCK_DGRAM 数据报套接字。
流式套接字采用数据流的形式,针对于面向连接的TCP服务
数据报形式针对于面向无连接的UDP协议。
除此之外 SOCK_RAW(原始)很少使用,我也没遇到所以不再细述。
int protocol 协议:默认为0
使用方法:int fd = sockfd(AF_INET,SOCK_STREAM,0)
bind()函数
为接收客户端请求,服务器端套接字需绑定ip以及端口才接收相应的连接请求。
bind函数的作用即为绑定ip地址及端口号。
这里引入了两结构体
sockaddr 以及sockaddr_in;
两种结构体为并列关系。
由于该处是简单讲解,不对其具体内容详细列出。
sockaddr定义于#include <sys/socket.h>
其中char sa_data[14]的字符数组用于存放目的端的ip以及端口,由于难以直接对其赋值,所以采用sockaddr_in结构体临时存放ip以及端口。
sockaddr_in{
short sin_family; /AF_INET 协议簇/
u_short sin_port; /端口号,网络字节顺序/
struct in_addr sin_addr; /IP地址,网络字节顺序/
char sin_zero[8]; /填充字节,必须为全零/
}
而结构体in_addr{
u_long S_addr; 用于存放相应的32IPv4地址。
}
bind(int socket,struct sockaddr *myaddr,int addrlen)
用于将ip地址与端口号绑定至对应的socket套接字中
参数列表:
int sockfd 定义需要绑定的socket套接字
struct sockaddr *myaddr 绑定对应的ip地址与端口、协议
int addrlen 地址长度
返回值:
-1失败
0成功
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr)); //用于对结构体进行初始化
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY); //INADDR_ANY绑定任何网络设备接口,适合于多IP主机以及IP地址经常变化的情况
servaddr.sin_port=htons(8086);
if(bind(fd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0) //在这里将sockaddr_in类型结构体强制转换成sockaddr
{
fprintf(stderr,"Bind error");
exit(1);
}
listen()函数
绑定地址端口后的socket作为监听socket,监听来自客户端的连接请求。
listen(int socket,int backlog)
参数列表:
int socket: :监听socket
int backlog :完成连接队列的最大长度。
返回值:
0成功
-1失败
TCP为每个监听socket维护两个队列信息。
其一为未完成连接的socket队列。
第二为已完成连接的socket队列,而backlog即为该队列长度。
if(listen(listenfd,BACKLOG)<0)
{
fprintf(stderr,"Listen error");
exit(1);
}
accept()函数
accept(int socket,struct sockaddr * addr,int addrlen)
参数列表
int socket :监听socket
struct sockaddr *addr :接受的客户端的地址内容
int addrlen : 结构体长度
返回值>0成功 这时返回的为连接后的socket;
=-1则为失败
int connfd=accept(listenfd,
(struct sockaddr *)&clientaddr,
sizeof(struct sockaddr_in));
connect()函数
客户端请求连接服务器的函数
###connect(int sockfd,struct sockaddr *servaddr,int addrlen)
参数列表:
sockfd-socket描述符
servaddr-服务器地址
addrlen-地址结构长度
返回值:
0成功
-1失败
客户端使用connect前,无需对socket进行绑定,通过connect与服务器建立连接之后,该套接字即可作为新的套接字使用。
具体使用方式:
struct sockaddr_in servaddr;
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(SERVER_PORT);
if(inet_aton(“127.0.0.1”,&servaddr.sin_addr)==-1) //inet_aton用于将字符串格式转为相应的ipv4格式的ip地址
{
fprintf(stderr,"Inet_aton error");
exit(1);
}
if(connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)
{
fprintf(stderr,"Connect error");
exit(1);
}
简单读写函数
write(int socket,char *buf,int len)
参数:
int socket :向指定的socket中写入数据
char *buf :写入的内容;
int length : buf的长度
返回值:
-1 失败
其他 返回写入内容的长度
系统发送缓冲区中空间大于参数len时返回len
read(int socket,char*buf,int len)
int socket :从指定的socket中写入数据
char *buf :希望读进的缓存区;
int length : 缓存区的长度
返回值:
-1 失败
其他 返回读入内容的长度
close()关闭套接字
close(int socket)
关闭socket
参数:
int socket :socket描述符
返回值
0-成功,-1-失败
示例代码如下:
服务器端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXDATASIZE 128
#define PORT 3000
#define BACKLOG 5
int main(int argc,char **argv){
int sockfd,new_fd,nbytes,sin_size;
char buf[MAXDATASIZE];
struct sockaddr_in servaddr,clientaddr;
//1.创建服务器网络端点
sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1){
printf("can't create socket\n");
exit(1);
}
//填充地址
bzero(&srvaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(PORT);
if(inet_aton("127.0.0.1",&servaddr.sin_addr)==-1){
printf("addr convert error\n");
exit(1);
}
//srvaddr.sin_addr.s_addr=htonl(INADDR_ANY);
//2.绑定服务器地址和端口
if(bind(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))==-1){
printf("bind error\n");
exit(1);
}
//3. 监听端口
if(listen(sockfd,BACKLOG)==-1){
printf("listen error\n");
exit(1);
}
for(;;){
//4.接受客户端连接
sin_size=sizeof(struct sockaddr_in);
if((new_fd=accept(sockfd,(struct sockaddr *)&clientaddr,&sin_size))==-1){
printf("accept errot\n");
continue;
}
printf("client ip:%s\n",inet_ntoa(clientaddr.sin_addr));
printf("client port:%d\n",ntohs(clientaddr.sin_port));
//5.接收请求
nbytes=read(new_fd,buf,MAXDATASIZE);
buf[nbytes]='\0';
printf("client:%s\n",buf);
//6.回送响应
sprintf(buf,"wellcome!");
write(new_fd,buf,strlen(buf));
//关闭socket
close(new_fd);
}
//关闭socket
close(sockfd);
return 0;
}
客户端
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXDATASIZE 128
#define PORT 3000
int main(int argc,char **argv){
int sockfd,nbytes;
char buf[MAXDATASIZE];
struct sockaddr_in servaddr;
//1.创建网络端点
sockfd=socket(AF_INET,
SOCK_STREAM,
0);
if(sockfd==-1){
printf("can;t create socket\n");
exit(1);
}
//指定服务器地址(本地socket地址采用默认值)
bzero(&servaddr,sizeof(servaddr));
srvaddr.sin_family=AF_INET;
srvaddr.sin_port=htons(PORT);
if(inet_aton("127.0.0.1",&servaddr.sin_addr)==-1){
printf("addr convert error\n");
exit(1);
}
//2.连接服务器
if(connect(sockfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr))==-1){
printf("connect error\n");
exit(1);
}
//3.发送请求
sprintf(buf,"hello");
write(sockfd,buf,strlen(buf));
//4.接收响应
if((nbytes=read(sockfd,buf,MAXDATASIZE))==-1){
printf("read error\n");
exit(1);
}
buf[nbytes]='\0';
printf("srv respons:%s\n",buf);
//关闭socket
close(sockfd);
return 0;
}