Socket网络编程
Posted konglingbin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Socket网络编程相关的知识,希望对你有一定的参考价值。
windows下的socket网络编程
已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先写了个简单的winSocket
网路通信的例子,以便以后用到的时候有个参考。
windows下使用winsock
编程与linux/unix
的区别在于windows下需要先有一个初始化
的操作,结束的时候需要一个清理
的操作。还有windows下编译的时候需要连接ws32_lib
库。
大致过程如下
-
1、初始化
/*加载Winsock DLL*/
WSADATA wsd;
if (WSAStartup(MAKEWORD(2 , 2) , &wsd) != 0) {
printf("Winsock 初始化失败!\\n");
return 1;
}
-
2、socket相关函数调用
socket(...)
bind(...)
listen(...)
connect(...)
accept(...)
send/sendto
recv/recvfrom
-
3、清理
WSACleanup();
clinet.c 客户端
客户端的流程很简单。
- 1、先是使用
socket
函数产生一个打开的socket
文件描述符。 - 2、使用
connect
函数去连接服务端 - 3、使用
read/recv
等读文件函数从服务端接收数据,使用write/send
等写文件的函数向服务端发送数据
上面是典型的TCP
编程流程,如果是UDP
的话不需要connect
去连接服务端直接使用sendto
函数来发送数据,使用recvfrom接收来自服务器的数据
server.c 服务器端
服务器端的流程比客户端稍微复杂一点
- 1、调用
socket
打开一个socket句柄 - 2、调用
bind
来绑定socket句柄到一个网口的某个端口 - 3、调用
listen
来设置(启用)监听 - 4、调用
accept
来等待客户端的连接
上面是典型的TCP
编程流程,如果是UDP
的,那么不需要3,4
这两部,直接使用recvfrom
来接收客户端发过来的数据即可。
UDP通信的实现
我这里没有写TCP
的,因为都是局域网内,就简单的写了个。
这里是在虚拟机里面测试的截图,代码见最后。
代码如下:https://www.cnblogs.com/oloroso/p/4613296.html
关于详细的服务器建立的步骤以及相关的socket套接字的知识我已经在python socket编程的文章中提到过了,大家可以参看那一篇博客来历接socket套接字编程的内容,由于要是用C相关的API所以这里采用了基于C语言的socket API编写相关的网络编程内容,具体的实现如下所示,调试通过
服务端Server.c程序内容:
1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <netdb.h> 6 #include <stdio.h> 7 #include <errno.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 /************************************************************************************************************************ 12 1、int socket(int family,int type,int protocol) 13 family: 14 指定使用的协议簇:AF_INET(IPv4) AF_INET6(IPv6) AF_LOCAL(UNIX协议) AF_ROUTE(路由套接字) AF_KEY(秘钥套接字) 15 type: 16 指定使用的套接字的类型:SOCK_STREAM(字节流套接字) SOCK_DGRAM 17 protocol: 18 如果套接字类型不是原始套接字,那么这个参数就为0 19 2、int bind(int sockfd, struct sockaddr *myaddr, int addrlen) 20 sockfd: 21 socket函数返回的套接字描述符 22 myaddr: 23 是指向本地IP地址的结构体指针 24 myaddrlen: 25 结构长度 26 struct sockaddr{ 27 unsigned short sa_family; //通信协议类型族AF_xx 28 char sa_data[14]; //14字节协议地址,包含该socket的IP地址和端口号 29 }; 30 struct sockaddr_in{ 31 short int sin_family; //通信协议类型族 32 unsigned short int sin_port; //端口号 33 struct in_addr sin_addr; //IP地址 34 unsigned char si_zero[8]; //填充0以保持与sockaddr结构的长度相同 35 }; 36 3、int connect(int sockfd,const struct sockaddr *serv_addr,socklen_t addrlen) 37 sockfd: 38 socket函数返回套接字描述符 39 serv_addr: 40 服务器IP地址结构指针 41 addrlen: 42 结构体指针的长度 43 4、int listen(int sockfd, int backlog) 44 sockfd: 45 socket函数绑定bind后套接字描述符 46 backlog: 47 设置可连接客户端的最大连接个数,当有多个客户端向服务器请求时,收到此值的影响。默认值20 48 5、int accept(int sockfd,struct sockaddr *cliaddr,socklen_t *addrlen) 49 sockfd: 50 socket函数经过listen后套接字描述符 51 cliaddr: 52 客户端套接字接口地址结构 53 addrlen: 54 客户端地址结构长度 55 6、int send(int sockfd, const void *msg,int len,int flags) 56 7、int recv(int sockfd, void *buf,int len,unsigned int flags) 57 sockfd: 58 socket函数的套接字描述符 59 msg: 60 发送数据的指针 61 buf: 62 存放接收数据的缓冲区 63 len: 64 数据的长度,把flags设置为0 65 *************************************************************************************************************************/ 66 int main(int argc, char *argv[]) 67 { 68 int fd, new_fd, struct_len, numbytes,i; 69 struct sockaddr_in server_addr; 70 struct sockaddr_in client_addr; 71 char buff[BUFSIZ]; 72 73 server_addr.sin_family = AF_INET; 74 server_addr.sin_port = htons(8000); 75 server_addr.sin_addr.s_addr = INADDR_ANY; 76 bzero(&(server_addr.sin_zero), 8); 77 struct_len = sizeof(struct sockaddr_in); 78 79 fd = socket(AF_INET, SOCK_STREAM, 0); 80 while(bind(fd, (struct sockaddr *)&server_addr, struct_len) == -1); 81 printf("Bind Success!\\n"); 82 while(listen(fd, 10) == -1); 83 printf("Listening....\\n"); 84 printf("Ready for Accept,Waitting...\\n"); 85 new_fd = accept(fd, (struct sockaddr *)&client_addr, &struct_len); 86 printf("Get the Client.\\n"); 87 numbytes = send(new_fd,"Welcome to my server\\n",21,0); 88 while((numbytes = recv(new_fd, buff, BUFSIZ, 0)) > 0) 89 { 90 buff[numbytes] = \'\\0\'; 91 printf("%s\\n",buff); 92 if(send(new_fd,buff,numbytes,0)<0) 93 { 94 perror("write"); 95 return 1; 96 } 97 } 98 close(new_fd); 99 close(fd); 100 return 0; 101 }
客户端Client.c程序内容:
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> int main(int argc,char *argv[]) { int sockfd,numbytes; char buf[BUFSIZ]; struct sockaddr_in their_addr; printf("break!"); while((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1); printf("We get the sockfd~\\n"); their_addr.sin_family = AF_INET; their_addr.sin_port = htons(8000); their_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); bzero(&(their_addr.sin_zero), 8); while(connect(sockfd,(struct sockaddr*)&their_addr,sizeof(struct sockaddr)) == -1); printf("Get the Server~Cheers!\\n"); numbytes = recv(sockfd, buf, BUFSIZ,0);//接收服务器端信息 buf[numbytes]=\'\\0\'; printf("%s",buf); while(1) { printf("Entersome thing:"); scanf("%s",buf); numbytes = send(sockfd, buf, strlen(buf), 0); numbytes=recv(sockfd,buf,BUFSIZ,0); buf[numbytes]=\'\\0\'; printf("received:%s\\n",buf); } close(sockfd); return 0; }
使用gcc编译器对客户端程序和服务端程序进行编译和解释:
gcc -o Master Server.c gcc -o Slave Client.c
编译的结果如下所示:
这时请先运行Master程序,然后再运行Slave程序:
在客户端Client输入要发送的内容:
一、IP地址操作类
1、IPAddress类
a、在该类中有一个 Parse()方法,可以把点分的十进制IP表示转化成IPAddress类,方法如下:
IPAddress address = IPAddress.Parse(“192.168.0.1”);
None 用于代表系统上没有网络接口
其中IPAddress.Any最常用可以用来表示本机上所有的IP地址,这对于socket服务进行侦听时,最方便使用,不用对每个IP进行侦听了。而IPAddress.Broadcase可用来UDP的IP广播,这些具体讲socket时再详细介绍。
2、IPEndPoint类
我们可以通过二种构造方法来创建IPEndPoint类:
a、IPEndPoint(long address, int port)
b、IPEndPoint(IPAddress address, int port)
四个属性:
这些应该从名字上就很好理解,不再一一介绍。IPEndPoint其实就是一个IP地址和端口的绑定,可以代表一个服务,用来Socket通讯。
二、DNS相关类
DNS类有四个静态方法,来获取主机DNS相关信息,
1、GetHostName()
通过Dns.GetHostName()可以获得本地计算机的主机名
2、GetHostByName()
根据主机名称,返回一个IPHostEntry 对象:
其中IPHostEntry把一个DNS主机名与一个别名和IP地址的数组相关联,包含三个属性:
3、GetHostByAddress()
类似于GetHostByName(),只不过这里的参数是IP地址,而不是主机名,也返回一个IPHostEntry对象。
4、Resolve()
当我们不知道输入的远程主机的地址是哪种格式时(主机名或IP地址),用以上的二种方法来实现,我们可能还要通过判断客户输入的格式,才能正确使用,但Dns类提供一更简单的方法Resolve(),该方法可以接受或者是主机名格式或者是IP地址格式的任何一种地址,并返回IPHostEntry对象。
1 extern int main_client(int , char**); 2 extern int main_server(int , char**); 3 4 int main(int c , char** v) 5 { 6 if (c == 3) { 7 main_client(c , v); 8 } 9 else { 10 main_server(c , v); 11 } 12 return 0; 13 14 }
以上是关于Socket网络编程的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段14——Vue的axios网络请求封装
VSCode自定义代码片段14——Vue的axios网络请求封装