Linux Sockt服务器和客户端开发示例
Sockt特点
1)传输数据为字节级,传输数据可自定义,数据量小(对于手机应用讲:费用低)
2)传输数据时间短,性能高
3)适合于客户端和服务器端之间信息实时交互
4)可以加密,数据安全性强
Sockt相关API
- socket——创建一个socket描述符
- bind——把地址和端口号组合赋给socket
- listen——监听socket
- accept——接受连接请求
- 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服务器和客户端开发的乐趣
作者:星辰~念
更多推荐



所有评论(0)