( 2018年11月29日 )
目录
补充知识点
1.套接字
- 源IP地址和目的IP地址以及源端口号和目的端口号的组合称为套接字。
- 其用于标识客户端请求的服务器和服务
2.地址结构sockaddr和sockaddr_in的区别
-
结构体struct sockaddr在/usr/include/linux/socket.h中定义
-
结构体struct sockaddr_in在/usr/include/netinet/in.h中定义(IPv4地址结构)
-
对比总结:
struct sockaddr是通用的套接字地址,而struct sockaddr_in则是internet环境下套接字的地址形式,两个结构体一样大,16个字节,都有family属性,不同的是:sockaddr用其余14个字节来表示sa_data,而sockaddr_in把14个字节拆分成sin_port, sin_addr和sin_zero分别表示端口、ip地址。sin_zero用来填充字节使sockaddr_in和sockaddr保持一样大小。sockaddr和sockaddr_in包含的数据都是一样的,但他们在使用上有区别:
程序员不应操作sockaddr,需要把sockaddr_in结构强制转换成sockaddr结构再传入系统调用函数中,sockaddr是给操作系统用的程序员应使用sockaddr_in来表示地址,sockaddr_in区分了地址和端口,使用更方便。 -
例:
int sockfd; struct sockaddr_in my_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); my_addr.sin_family = AF_INET; /* 主机字节序 */ my_addr.sin_port = htons(MYPORT); /* short, 网络字节序 */ my_addr.sin_addr.s_addr = inet_addr("192.168.0.1"); bzero(&(my_addr.sin_zero), 8); /* zero the rest of the struct */ //memset(&my_addr.sin_zero, 0, 8); bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
3.exit()、fork() - 基于 Linux
exit()
- 在Linux系统下,return是程序返回,而exit()函数是程序结束标识,
参数为0时,即exit(0)表示程序正常退出,非0表示非正常退出,但
具体是1还是-1,没有特别的规定,可以自己定义其含义。
fork()
在Linux中fork函数是非常重要的函数,它的作用是从已经存在的进程中创建一个子进程,而原进程称为父进程。
#include<unistd.h>//引用fork时的头文件
pid_t fork(void);//fork的返回类型为空1
-
调用fork(),当控制转移到内核中的fork代码后,内核开始做:
1.分配新的内存块和内核数据结构给子进程。
2.将父进程部分数据结构内容拷贝至子进程。
3.将子进程添加到系统进程列表。
4.fork返回开始调度器,调度。#include<stdio.h> #include<unistd.h> #include<stdlib.h> int main() { pid_t pid; printf("before :pid is %d\n",getpid()); if((pid=fork())==-1) perror("fork()"),exit(1); printf("After:pid=%d,fork return %d\n",getpid(),pid); sleep(1); return 0; }
·调用一次,返回两次
fork函数被父进程调用一次,但是却返回两次;一次是返回到父进程,一次是返回到新创建的子进程。
·注意
•并发执行
子进程和父进程是并发运行的独立进程。内核能够以任意的方式交替执行他们的逻辑控制流中的指令。在我们的系统上运行这个程序时,父进程先运行它的printf语句,然后是子进程。
•相同但是独立的地址空间
因为父进程和子进程是独立的进程,他们都有自己私有的地址空间,当父进程或者子进程单独改变时,不会影响到彼此,类似于c++的写实拷贝的形式自建一个副本。
•fork的返回值
1.fork的子进程返回为0;
2.父进程返回的是子进程的pid。
•fork的常规用法
1.一个父进程希望复制自己,使得子进程同时执行不同的代码段,例如:父进程等待客户端请求,生成一个子进程来等待请求处理。
2.一个进程要执行一个不同的程序。
•fokr调用失败的原因
1.系统中有太多进程
2.实际用户的进程数超过限制
◎解析代码◎
Socket_demo _udp
实验路径**/home/rain/Socket_exp/Socket_UDP_demo 实验环境 - Linux
ser.c - 建立socket服务器
//头文件:
stdio.hunistd.h
sys/types.hsys/socket.h
arpa/inet.h
//定义端口号:PORT - ( 0 - 65535 ) - 1024以下端口号保留预定义服务
1.创建Socket对象
int socket_fd = socket( AF_INET , SOCK_DGRAM , 0 )
if( socket_fd == -1 )
{
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
//OR perror("socket failed");
exit(-1);
}
2.创建网络通信对象
struct sockaddr_in addr;
addr.sin_family =AF_INET;
addr.sin_port =htons(PORT);
addr.sin_addr.s_addr=inet_addr("192.168.18.136");
//OR addr.sin_addr.s_addr=inet_addr("127.0.0.1");
3.绑定socket对象与通信连接
int ret =bind(socket_fd,(struct sockaddr*)&addr,sizeof(addr));
if(0>ret)
{
printf("bind\n");
return -1;
}
4.交换数据
struct sockaddr_in cli;
socklen_t len=sizeof(cli);
char buf[4096] = {0};char p[] = "Successful receipt\n";char *s = p;
while(1)
{
recvfrom(socket_fd,&buf,sizeof(buf),0,(struct sockaddr*)&cli,&len);
printf("recv : %s\n",buf);
sendto(socket_fd,&p,sizeof(p),0,(struct sockaddr*)&cli,len);
}
close(socket_fd);
cli.c - 建立socket客户端
//头文件:
stdio.hunistd.h
sys/types.hsys/socket.h
arpa/inet.h
//定义端口号:PORT - ( 0 - 65535 ) - 1024以下端口号保留预定义服务
1.创建Socket对象
int sockfd=socket(AF_INET,SOCK_DGRAM,0); /*建立数据报套接字*/
2.创建网络通信对象
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr)); /*清空地址结构*/
addr.sin_family =AF_INET;/*地址类型为AF_INET*/
addr.sin_port =htons(PORT);
addr.sin_addr.s_addr = inet_addr("127.0.0.1"); //IP-> 服务器
3.交换数据
printf("Input:");
char buf[4096]={0}; scanf("%s",buf);
sendto(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&addr,sizeof(addr));
socklen_t len=sizeof(addr);
inr i = recvfrom(sockfd,&buf,sizeof(buf),0,(struct sockaddr*)&addr,&len);
if(i !=-1)
{ printf(" server 成功接受\n"); }
else
{ printf("server 数据丢失\n");}
printf("服务器返回数据 : %s\n",buf);
close(sockfd);
//注:可参照Socket编程-③tcp代码实例+解析,运用main函数参数,实现合理化进入
·socket_fd - /套接字文件描述符/
工程代码
https://download.youkuaiyun.com/download/qq_42819325/89139735