一、写socket服务器代码,
因为一直在看别人写的代码,其实自己没有真正意义上的写代码,永远也理解不了,所以要尝试自己写一下客户机和服务器的代码。先弄懂所需要的所有函数。
总结一下,要有以下函数:
服务器端:6个主要函数
socket()://不管是客户机还是服务器,都需要SOCKET函数来创建一个套接字。
bind()://绑定已有的socket和自己服务器的端口号,因为通信的过程是通过端口号进行的。
listen()://监听端口号上是否有动静,因为它是服务器嘛。
accepc():如果端口号有包发来,就接收一下,来自客户端的请求。
recv()://从socket中读取字符,我一直以为accept是读取信息,recv是接收,原来是错的,accept是接收,recv才是收了之后去读。
close():关闭套接字,通信就结束了。
客户机端:4个主要函数
socket()://创建一个套接字
connect()://连接到服务器
send()://向服务器发送信息
close():关闭
下面详细分解一下这几个函数
1、创建套接字socket()
SOCKET PASCAL FAR socket(int af, int type, int protocol)
af:通信发生的区域,AF_INET 和PF_INET都一样
type:上层协议的类型,SOCK_STREAM,流-TCP协议 SOCT_DGRAM-数据报,UDP
protocol指定哪个协议,一般为0
所以如果是TCP协议,这里就定议为 socket(AF_INET,SOCK_STREAM,0)
2、指定本地地址──bind()
int PASCAL FAR bind(SOCKET s, const struct sockaddr FAR * name, int namelen);
SOCKET s是套接字描述符,name是本地地址名,namelen表明name的长度,如果出错,bind()返回0,
3、建立套接字连接——connect()和accept()
int PASCAL FAR connect(SOCKET s, const struct sockaddr FAR * name, int namelen);
s 本地套接字的描述符,name是服务器地址名,namelen表明name的长度,如果出错,connect()返回0
SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);
accept()用于面向连接服务器。参数addr和addrlen存放客户方的地址信息,s 本地套接字的描述符,addr是客户地址,addrlen是客户地址长度。
4、监听连接──listen()
int PASCAL FAR listen(SOCKET s, int backlog);
s本地已建立未连接的套接字号,backlog表示请求连接的最大长度。用于限制请求个数。
5、数据传输──send()与recv()
int PASCAL FAR send(SOCKET s, const char FAR *buf, int len, int flags);
s为本地套接字,buf指向有发送数据缓存的指针,len是这个指针的长度,flags指定传输控制方式,
int PASCAL FAR recv(SOCKET s, char FAR *buf, int len, int flags);
s:描述符,buf指向缓存的指针,len长度,flags是传输控制方式。
6、关闭套接字──closesocket()
BOOL PASCAL FAR closesocket(SOCKET s);
closesocket()关闭套接字s,并释放分配给该套接字的资源;
附上代码
server.c
#include
#include
#include
#include
#include
#include
#include
int main(int argc,char *argv[])
{
int socket_serv;
int socket_cli,cli_add_len;
struct sockaddr_in serv_addr,cli_addr;
char message[]="hello my client!";//给客户机发一个消息,证明成功连接
memset(&serv_addr,0,sizeof(serv_addr));//清零
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=INADDR_ANY;//all 本地的所有地址,指定也可以
serv_addr.sin_port=htons(6666);//端口号,指定.htons是将整型变量从主机字节顺序转变成网络字节顺序
if((socket_serv=socket(PF_INET,SOCK_STREAM,0))<0)
{
printf("socket()error");
}
int opt=1;
setsockopt(socket_serv,SOL_SOCKET ,SO_REUSEADDR,(const char*)&opt,sizeof(opt));//6666这个端口号可以一直被反复使用
if((bind(socket_serv,(struct sockaddr*)&serv_addr,sizeof(serv_addr)))<0)//绑定本地地址;
{
printf("bind()error\n");
}
if((listen(socket_serv,10))<0)
{
printf("listen()error\n");
}
cli_add_len=sizeof(cli_addr);
socket_cli=accept(socket_serv,(struct sockaddr*)&cli_addr,&cli_add_len);//注意第二和第三个参数,接收的是客户端的地址,第三个参数为客户端的地址长度指针……
if(socket_cli==-1)
{
printf("accept()error");
}
printf("accept client %s\n",inet_ntoa(cli_addr.sin_addr));
write(socket_cli,message,sizeof(message));//三个参数,写给socket_cli,就连接socket_cli
close(socket_serv);
close(socket_cli);
return 0;
/*已建立连接,如何把收到的消息打印出来?*/
}
client.c
#include
#include
#include
#include
#include
#include
#include
int main(int agrc,char* agrv[])
{
int sock,str_msg;
char message[30];
struct sockaddr_in serv_addr;
sock=socket(PF_INET,SOCK_STREAM,0);
if(sock==-1)
{
printf("socket()error\n");
}
memset(&serv_addr,0,sizeof(serv_addr));
serv_addr.sin_family=AF_INET;
serv_addr.sin_addr.s_addr=inet_addr("192.168.2.29");
serv_addr.sin_port=htons(6666);
if(connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr))<0)
{
printf("connect()error");
}
str_msg=read(sock,message,sizeof(message)-1);
if (str_msg==-1)
{
printf("read()error");
}
printf("Message from server :%s\n",message);
close(sock);
return 0;
}
二、写ZMQ通信与TCP/IP socket进行对比