Sockt特点

1)传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低)
2)传输数据时间短,性能高
3)适合于客户端和服务器端之间信息实时交互
4)可以加密,数据安全性强

Sockt相关API

  1. socket——创建一个socket描述符
  2. bind——把地址和端口号组合赋给socket
  3. listen——监听socket
  4. accept——接受连接请求
  5. connect——发出连接请求
    在这里插入图片描述

一、socket——创建一个socket描述符

1.原函数

表头文件
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
定义函数
int socket(int domain, int type, int protocol);

函数说明——创建一个socket描述符,这个socket描述字跟文件描述字一样,后续的操作都有用到它,把它作为参数,通过它来进行一些读写操作
int domain —— 指明所使用的协议族,通常为AF_INET表示互联网协议族(TCP/IP)
int type —— socket的类型(SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等)
int protocol —— 通常赋值0,根据以上参数自动选出对应传输协议
返回值——成功返回套接字的文件描述符。错误返回-1,并设置errno

2.示例

int soc1=socket(PF_INET,SOCK_STREAM,0);//TCP协议,返回socket描述符

二、bind——把地址和端口号组合赋给socket

1.原函数

表头文件
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
定义函数
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//参数需用到头文件:#include <arpa/inet.h>

函数说明——把一个地址族中的特定地址赋给socket,如把地址和端口号组合赋给socket
int sockfd —— socket返回值
const struct sockaddr *addr —— 结构体内包含所需的IP地址和端口号(服务器的)
socklen_t addrlen —— sockaddr的结构体长度
返回值——成功返回0。错误返回-1,并设置errno

2.参数取值
struct sockaddr 结构体如下:

struct sockaddr {
               sa_family_t sa_family;		//协议族
               char        sa_data[14];		//IP+端口
           }

通常使用struct sockaddr_in 结构体同等替换(使用时需要强转类型):

struct sockaddr_in {
    sa_family_t    sin_family;		//协议族
    in_port_t      sin_port;   		//端口号
    struct in_addr sin_addr;   		//IP地址结构体
    unsigned char sin_zero[8];		//填充,为了与sockaddr结构内存对齐,两者才能相互替换
};

struct in_addr {
    uint32_t       s_addr;     
};

3.示例

int soc1=socket(PF_INET,SOCK_STREAM,0);//创建套接字
int count=0;

struct sockaddr_in soc_in;
struct in_addr in_a;
memset(&soc_in,0,sizeof(struct sockaddr_in));	
memset(&in_a,0,sizeof(struct in_addr));	

soc_in.sin_family=PF_INET;
soc_in.sin_port=htons(atoi(argv[2]));//配置网络端口号
inet_aton(argv[1],&in_a);//将网络ip地址转成网络二进制的数字然后存储在in_a.s_addr里
soc_in.sin_addr.s_addr=(in_a.s_addr);//配置网络IP地址

bind(soc1,(struct sockaddr *)&soc_in,sizeof(struct sockaddr_in));//把地址和端口号组合赋给socket

三、listen——监听socket

1.原函数


```c
表头文件
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
定义函数
int listen(int sockfd, int backlog);

函数说明——listen()来监听这个socket,如果客户端这时调用connect()发出连接请求,服务器端就会接收到这个请求,accept()来响应请求
int sockfd —— socket返回值
int backlog —— 监听的数量即最大连接个数
返回值——成功返回0。错误返回-1,并设置errno

2.示例

int soc1=socket(PF_INET,SOCK_STREAM,0);

listen(soc1,10);

四、accept——接受连接请求

1.原函数

表头文件
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
定义函数
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

函数说明——connect()发起连接请求,accept()响应请求,返回值可以用来后续的数据读写
int sockfd —— socket返回值
struct sockaddr *addr —— 用来返回已连接的对端(客户端)的协议地址
socklen_t *addrlen —— 此协议地址长度
返回值——成功返回新套接字的描述符。错误返回-1,并适当地设置errno

2.示例

struct sockaddr_in soc_on;
int len=sizeof(struct sockaddr_in);
int acc=accept(soc1,(struct sockaddr *)&soc_on,&len);//返回新的Sockt描述字

五、connect——发出连接请求

1.原函数

表头文件
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
定义函数
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

函数说明——connect()发起连接到struct sockaddr指定的网络地址
int sockfd —— socket的返回值
const struct sockaddr *addr —— 服务器的socket地址、端口号
socklen_t addrlen —— sockaddr的结构体的长度
返回值——成功则返回0,失败返回-1,错误原因存于errno中

2.示例

int soc1=socket(PF_INET,SOCK_STREAM,0);
connect(soc1,(struct sockaddr *)&soc_in,sizeof(struct sockaddr_in));

Sockt服务器和客户端例程演示

服务端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include "sys/types.h"
#include "sys/socket.h"
#include <arpa/inet.h>
#include "netinet/in.h"
#include "arpa/inet.h"
#include <unistd.h>

int main(int argc,char **argv)
{
	int acc;
	char str1[128]={'\0'};
	char str2[128]={'\0'};
	int len1;
	int soc1=socket(PF_INET,SOCK_STREAM,0);//创建套接字
	int count=0;

	struct sockaddr_in soc_in;
	struct in_addr in_a;
	memset(&soc_in,0,sizeof(struct sockaddr_in));	
	memset(&in_a,0,sizeof(struct in_addr));	

	soc_in.sin_family=PF_INET;
	soc_in.sin_port=htons(atoi(argv[2]));
	inet_aton(argv[1],&in_a);
	soc_in.sin_addr.s_addr=(in_a.s_addr);

	bind(soc1,(struct sockaddr *)&soc_in,sizeof(struct sockaddr_in));//把服务器地址和端口号组合赋给socket

	listen(soc1,10);//监听连接请求

	struct sockaddr_in soc_on;
	int len=sizeof(struct sockaddr_in);
	while(1)
	{
		count++;
		acc=accept(soc1,(struct sockaddr *)&soc_on,&len);//接受连接请求
		if(fork()==0)//创建子进程,让子进程与连接好的客服端完成对接
		{
			if(fork()==0)
			{
				while(1)
				{
					memset(str2,'\0',sizeof(str2));
					sprintf(str2,"count=%d",count);
					len1=send(acc,(void *)str2,sizeof(str2),0);//向客服端发送数据
					sleep(3);
				}
			}
			while(1)
			{
				len1=recv(acc,(void *)str1,sizeof(str1),0);//接收客服端数据
				if((len1==-1)||(len1==0))
				{
					printf("This is:%d\n",count);
					exit(-1);
				}
				printf("接收:len1=%d,str1=%s\n",len1,str1);
			}
		}
	}
	
	return 0;
}

客服端

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "sys/types.h"
#include "sys/socket.h"
#include <arpa/inet.h>
#include "arpa/inet.h"

int main(int argc,char **argv)
{
	int soc1=socket(PF_INET,SOCK_STREAM,0);//创建套接字
	char str1[128]={'\0'};
	char str2[128]={'\0'};
	int len;	

	struct sockaddr_in soc_in;
	struct in_addr in_a;
	memset(&soc_in,0,sizeof(struct sockaddr_in));
    memset(&in_a,0,sizeof(struct in_addr)); 

	soc_in.sin_family=PF_INET;
	soc_in.sin_port=htons(atoi(argv[2]));
	inet_aton(argv[1],&in_a);
	soc_in.sin_addr.s_addr=(in_a.s_addr);

	connect(soc1,(struct sockaddr *)&soc_in,sizeof(struct sockaddr_in));//发起连接到struct sockaddr指定的网络地址

	while(1)
	{
		if(fork()==0)//创建子进程与服务端完成对接
		{
			if(fork()==0)
			{
				memset(str2,'\0',sizeof(str2));
				len=recv(soc1,(void *)str2,sizeof(str2),0);//接收服务端数据
				if((len==-1)||(len==0))
				{
					printf("error\n");
					exit(-1);
				}
				printf("接收:len=%d,str2=%s\n\n",len,str2);
			}
			while(1)
			{
				memset(str1,'\0',sizeof(str1));
				gets(str1);
				len=send(soc1,(void *)str1,sizeof(str1),0);//向服务端发送数据
			}
		}
	}

	return 0;
}

运行结果:打开服务端后,可打开多个客户端连接服务端进行对接,通信可双向

读者可亲自实验Sockt服务器和客户端开发的乐趣
作者:星辰~念

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐