纯新系列文章
第三章:网络编程(socket)
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
?? hello!大家好,本节内容是纯新系列内容的第三节,网络编程,前两节分别为进程和线程,感兴趣的朋友可以通过点击结尾的链接来学习。
提示:以下是本篇文章正文内容。
一、IP地址,端口和协议
?? IP地址:Internet中唯一的地址标识,目前广泛使用的ip地址为32位(4个字节),每一个Internet都必须带有IP地址。 ?? 表示:每个字节的数字用十进制表示并用点隔开。 (111.111.23.111) ??端口(TCP\Udp):目的主机接收到数据包后可通过端口传递给运行进程中的某一个。 ??大小:0~65536 ??协议 :一种通信规则,有TCP[传输控制协议] 和UDP[用户数据报协议]两种协议
??区别:TCP 协议可以看做是打电话,必须在对方的同意下才能传输数据,UDP协议就好比发短信,用户只管发,并不知道对方有没有收到,这种情况可能会造成丢数据的情况,所以UDP经常会出现在视音频的传输中。
二、相关知识点
1.数据结构:sockaddr_in
?? 在网络编程中,操作系统本身以结构体struct sockaddr来存储相关地址信息,但程序员无法 直接使用结构体struct sockaddr,而是通过操作struct sockaddr_in来间接向struct sockaddr写入数据,在字节上,两者是等大的,下面是struct sockaddr的的结构体组成
struct in_addr{
unsigned long s_addr;
};
struct sockaddr_in{
short int sin_family;
unsigned short in sin_port;
struct in_addr;
unsigned char sin_zero[8];
};
int main()
{
struct sockaddr_in my_addr;
memset(&my_addr,0,sizeof(my_addr));
my_addr.sin_family=AF_INEF;
my_addr.sin_port= htons(3490);
my_addr.sin_addr.s_addr=inet_addr("135.241.5.10");
}
?? 补充:上面的程序涉及到了一些变量的转换函数,程序如下
#include <apra/inet.h>
in_addr_t inet_addr(const char *strptr);
char *inet_ntoa(struct in_addr inaddr);
#include <apra/inet.h>
uint32_t htons(uint16_t hostshort);
2.字节顺序
?? 主机字节顺序:指的是整数在内存中保存的顺序,不同的CPU有不同的顺序,有小端字节序和大端字节序之分。 网络字节顺序: TCP/IP协议规定,网络数据流应采用大端字节序,既低地址高字节
#include <apra/inet.h>
uint32_t htonl(uint 32_t hostlong);
uint32_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint32_t ntohl(uint16_t netshort);
3.模型
?? 在编程之前,我们首先要知道如下的模型
三.Socket编程
socket()
?? socket:它一个描述符。类似于文件中的文件描述符
int socket(int flmily,int type,int protocol);
connect()
?? 该函数是为了在客户端建立于服务器的连接
int connect(int sockfg,struct sockaddr *servaddr , int addrlen);
读写操作
#include <unistd.h>
ssize_t read(int fa,void *buf,size_t count);
ssize_t write(int fd,const void *buf,size_t count);
#include <sys/types.h>
#include <sys/socket.h>
int recv(int sockfd,void *buf ,int len,int flags);
int send(int sockfd,const void *msg,int len,int flags);
ssize_t sendto(int sock,const void * buf,size_t len,inf flags ,const struct sockaddr * to, socklen_t tolen);
ssize_t recvfrom(int sockfd,void *buf,size_t len,int flags,struct sockaddr * from,socklen_t *addrlen);
close()
?? 用来关闭特定的socket连接
int close(int sockfd);
客户端实战TCP
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <error.h>
#include <unistd.h>
#include <string.h>
int main()
{
char buf[1024]={0};
struct sockaddr_in sevAddr;
memset(&sevAddr,0,sizeof(sevAddr));
sevAddr.sin_family = AF_INET;
sevAddr.sin_port = htons(8899);
sevAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int sockfd = socket(AF_INET,SOCK_STREAM,0);
if(sockfd == -1)
{
perror("socket");
return 0;
}
if(connect(sockfd,(struct sockaddr *)&sevAddr ,sizeof(sevAddr))==-1)
{
perror("connect");
return -1;
}
printf("oj");
pid_t pid=fork();
while(1)
{
if(pid == 0)
{
if(read(sockfd,buf,sizeof(buf))==0)
{
exit(0);
}
printf("buf=%s\n",buf);
memset(buf,0,sizeof(buf));
}
if(pid>0)
{
write(sockfd,"okok",strlen("okok"));
}
}
close(sockfd);
return 0;
}
提示:读写函数都具有阻塞的特性,为了不影响收发(随时收和发,互不影响)上面的函数我用了两个进程分别来写收发,当然也有不用进程的方法,比如说select()可以判断出读端和写段的事件,我们放在服务器中讲述。
bind()
?? 服务器用来绑定端口的函数,出错返回-1
int bind(int sockfd,struct sockaddr * my_addr,int addrlen);
listen()和accept()
?? listen的作用相当于一个接收队列,当一个新的请求被放在接收队列中,服务器调用accept()函数来接收请求
int listen(int sockfd ,int queue_length);
int accept(int sockfd,struct sockaddr *addr ,int *addrlen);
select()
?? select()函数的作用是允许进程提示内核等待多某一或多个事件发生或经历一段时间后唤醒他。正确返回就绪描述符的个数,超时返回0,出错返回-1。
int select(int maxfd,fd_set *readset,fd_*writeset,fd_set *exceptset,const struct timeval*timeout)
fd _set read;
void ZD_ZERO(fd_set *fdest);
void FD_SET(int fd,fd_set *fdest);
void FD_CLR(int fd,fd_set *fdset);
void FD_ISSET(int fd,fd_set *fdset);
服务端TCP
include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <error.h>
int main()
{
struct sockaddr_in myaddr;
struct sockaddr_in clientaddr;
int clilen = sizeof(clientaddr);
memset(&clientaddr,0,sizeof(clientaddr));
memset(&myaddr,0,sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("10.32.556.192");
int listfd = socket(AF_INET,SOCK_STREAM,0);
if(listfd == -1)
{
perror("socket");
return -1;
}
if(bind(listfd,(struct sockaddr *)&myaddr,sizeof(myaddr)) == -1)
{
perror("bind");
return -1;
}
if(listen(listfd,5) == -1)
{
perror("listen");
return -1;
}
int confd=0;
char buf[120]={0};
while(1)
{
confd=accept(listfd,(struct sockaddr *)&clientaddr,&clilen);
if(confd == -1)
{
perror("accept");
return -1;
}
read(confd,buf,sizeof(buf));
printf("buf = %s\n",buf);
printf("addr = %s port = %d\n",inet_ntoa(clientaddr.sin_addr),ntohs(clientaddr.sin_port));
}
clost(listfd);
return 0;
}
其他函数
int getsockname(int sockfd,struct sockaddr *localaddr,socklen_t *addrlen);
int getsockopt(int sockfd,int level,int optname ,void *optavl,socklen_t *optlen);
int setsockpt(int sockfd ,int level,int optname,const void *optval,socklen_t optlen);
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,(void *)&val,sizeof(val));
struct ip_mreqn mry;
memest(&mrq,0,sizeof(mrq));
mry.imr_multiaddr.s_addr = inte_addr(224.20.10.1");
mry.imr_address.s_addr = htonl(INADDR_ANY):
setsockopt(sockfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mry,sizeof(mry));
udp客户端
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <error.h>
#include <arpa/inet.h>
int main()
{
char buf[1024]={0};
struct sockaddr_in addr;
memset(&addr,0,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8899);
addr.sin_addr.s_addr = inet_addr("10.32.56.192");
int sockfd = socket(AF_INET,SOCK_DGRAM,0);
if(sockfd == -1)
{
perror("select");
return -1;
}
while(1)
{
memset(buf,0,sizeof(buf));
scanf("%s",buf);
sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&addr,sizeof(addr));
}
return 0;
}
~
udp服务端
#include <error.h>
#include <unistd.h>
#include <arpa/inet.h>
int main()
{
struct sockaddr_in saddr;
struct sockaddr_in caddr;
char buf[1024]={0};
int clent = sizeof(caddr);
memset(&saddr,0,sizeof(saddr));
memset(&caddr,0,sizeof(caddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(8899);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
int confd = socket(AF_INET,SOCK_DGRAM,0);
if(confd == -1)
{
perror("select");
return -1;
}
if(bind(confd,(struct sockaddr *)&saddr,sizeof(saddr))==-1)
{
perror("bind");
return -1;
}
while(1)
{
recvfrom(confd,buf,sizeof(buf),0,(struct sockaddr *)&caddr,&clent);
printf("%s \n",buf);
sendto(confd,"ok",2,0,(struct sockaddr *)&caddr,sizeof(caddr));
memset(buf,0,sizeof(buf));
}
return 0;
}
总结
?? 以上就是今天所要分享的代码了 ?? 学习路漫漫,我们仍需负重前行…… ?? 为此博主新创建了一个群,正等待你们的加入: ?? QQ群:928357277
上一章:纯新多线程【点击学习】
|