本篇blog学习于基于Linux平台使用socket实现 一个最简单的聊天系统,并详细演示了demo,同时对代码做了更加详细的注解,方便学习。
socket()函数
创建套接字
在 Linux 下使用 <sys/socket.h> 头文件中 socket() 函数来创建套接字.
原型为:int socket(int af, int type, int protocol);
1.af:地址族(Address Family),也就是 IP 地址类型,常用为AF_INET 和 AF_INET6
2.type:type为数据传输方式/套接字类型.
常用的有SOCK_STREAM(流格式套接字/面向连接的套接字)和SOCK_DGRAM(数据报套接字/无连接的套接字)
3.protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议。
bind()函数
绑定端口
服务器端要用 bind() 函数将套接字与特定的 IP 地址和端口绑定起来
int bind(int sock, struct sockaddr *addr, socklen_t addrlen); //Linux
1.sock 为 socket 文件描述符
2.addr 为 sockaddr 结构体变量的指针
3.addrlen 为 addr 变量的大小,可由 sizeof() 计算得出。
sockaddr_in 结构体
struct sockaddr_in{
sa_family_t sin_family; //地址族(Address Family),也就是地址类型
uint16_t sin_port; //16位的端口号
struct in_addr sin_addr; //32位IP地址
char sin_zero[8]; //不使用,一般用0填充
};

listen() 函数
表示让一个套接字处于监听到来的连接请求的状态
listen() 函数可以让套接字进入被动监听状态
原型为int listen(int sock, int backlog); //Linux
sock 为需要进入监听状态的套接字,backlog 为请求队列的最大长度。
accept() 函数
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。
原型为:int accept(int sock, struct sockaddr *addr, socklen_t *addrlen); //Linux
accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字
send()函数和recv()函数
示例图参考recv( )函数返回值说明

int send( SOCKET s, const char FAR *buf,int len, int flags );
参数说说明
第一个参数指定发送端套接字描述符;
第二个参数指明一个存放应用程序要发送数据的缓冲区;
第三个参数指明实际要发送的数据的字节数;
第四个参数一般置0。
===============================================================
int recv( SOCKET s, char FAR *buf, int len, int flags);
参数说明
第一个参数指定接收端套接字描述符;
第二个参数指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据;
第三个参数指明buf的长度;
第四个参数一般置0。
server.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#define PORT 6666
#define BACKLOG 10
#define MAX_SIZE 2048
int main()
//定义服务器socket的描述符
int socket_fd;
//定义套接字的地址形式
struct sockaddr_in server_addr;
char buffer[MAX_SIZE]={0};
char message[MAX_SIZE];
//建立套接字
socket_fd = socket(AF_INET,SOCK_STREAM,0);
//bzero函数的作用是将s指针指向的地址的前n个字节清零
bzero(&server_addr,sizeof(server_addr));
//填写信息
server_addr.sin_family = AF_INET;
server_addr.sin_port=htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
//绑定端口
bind(socket_fd,(struct sockaddr *)&server_addr,sizeof(server_addr));
//开始监听
listen(socket_fd,BACKLOG);
printf("Server bind success \n");
// 定义客户端socket的描述符
struct sockaddr_in peer_addr;
socklen_t peer_len = sizeof(peer_addr);
while(1)
{
int client_fd;
/*
*SOCKET accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
*服务器调用accept函数从处于监听状态的流套接字sd的客户连接队列中
*取出排在最前面的的一个客户连接请求,
*并创建一个与sd同类的新套接字描述符与客户端套接字创建连接通道。
*/
client_fd = accept(socket_fd,(struct sockaddr* )&peer_addr,&peer_len);
printf("Receive a connect from clinet fd[%d,ip:%s,port:%d]\n",
client_fd,inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
while (1)
{
memset(buffer,0,sizeof(buffer));
int recv_len = recv(client_fd,buffer,MAX_SIZE,0);
if(recv_len == 0)
{
printf("Clinet is already closed\n");
break;
}
else
{
printf("Recv len is %d \n",recv_len);
}
printf("Clinet says:\n");
strcpy(message,buffer);
fputs(message,stdout);
memset(buffer,0,MAX_SIZE);
printf("Please input:\n");
fgets(buffer,sizeof(buffer),stdin);
send(client_fd,buffer,recv_len,0);
}
close(client_fd);
break;
}
close(socket_fd);
printf("Server exit\n");
return 0;
}
client.cpp
#include
#include
#include
#include
#include
#include
#include
#include
#define CLIETN_PORT 6666
#define MAX_SIZE 2048
int main(int argc,char *argv[])
{
if(argc != 2)
{
printf("Please input server ip\n");
exit(1);
}
char buffer[MAX_SIZE];
//建立
int socket_fd = socket(AF_INET,SOCK_STREAM,0);
const char *server_ip = argv[1];
struct sockaddr_in server_addr;
bzero(&server_addr,sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(CLIETN_PORT);
//inet_pton是一个IP地址转换函数,可以在将点分文本的IP地址转换为二进制网络字节序”的IP地
inet_pton(AF_INET,server_ip,&server_addr.sin_addr);
connect(socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr));
printf("Connect to server success\n");
memset(buffer,0,MAX_SIZE);
printf("Please input:\n");
while (fgets(buffer,sizeof(buffer),stdin) != NULL)
{
if(strncmp(buffer,"quit",4) == 0)
{
printf("intpu is: quit break\n");
break;
}
else
{
printf("intpu is: %s\n",buffer);
}
send(socket_fd,buffer,strlen(buffer),0);
memset(buffer,0,sizeof(buffer));
recv(socket_fd,buffer,sizeof(buffer),0);
printf("Server says:\n");
fputs(buffer,stdout);
memset(buffer,0,sizeof(buffer));
printf("Please input:\n");
}
printf("Client will be closed\n");
close(socket_fd);
return 0;
}
首先,我们先执行文件的编译,接着先./server,然后再执行./client,注意:client后面要加上ip。具体如下图所示.

参考资料:
http://c.biancheng.net/view/2344.html