TCP的三次握手(图片来自百度百科)
TCP的四次分手(图片来自百度百科)
单向交互套结字
服务端
描述符,sfp接收所有连接请求,然后将每个连接传给对应的一个nfp。类似电话总机与分机。
/*
* Author: xusongqi@live.com
*
* Created Time: 2014年03月19日 星期三 17时29分14秒
*
* FileName: sock_server.c
*
* Description:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <linux/in.h>
#include <string.h>
#include <sys/socket.h>
int main(void)
{
int sfp,nfp;//两个描述符
struct sockaddr_in server_addr,client_addr;//服务器地址,客户端地址
int sin_size;//???
unsigned short portnum = 0x8888;//服务器使用端口
printf("Here's a socket server\n");
sfp = socket(AF_INET, SOCK_STREAM,0);
if(sfp == -1)
{
printf("SOCKET FAILED\n");
exit(1);
}
printf("SOCKET SUCCEED\n");
/*设置监听的端口和IP信息*/
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(portnum);
/*bind() 端口绑定函数*/
if(-1 == bind(sfp,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)))
{
printf("BIND FAILED\n");
exit(1);
}
printf("BIND SUCCEED\n");
/*listen 监听端口函数*/
if(-1 == listen(sfp,5))
{
printf("LISTEN FAILED\n");
exit(1);
}
printf("LISTEN SUCCEED\n");
while(1)
{
sin_size = sizeof(struct sockaddr_in);
/*服务端accept函数,调用即进入阻塞状态,等待用户连接。
*在没有用户进行连接时,程序停在此处。
*此处accpet的第二个参数用于获取客户端的端口和地址信息。
*/
nfp = accept(sfp,(struct sockaddr *)(&client_addr),&sin_size);
if(nfp == -1)
{
printf("ACCEPT FAILED\n");
exit(1);
}
printf("ACCEPT SUCCEED\nSERVER START GET CONNECT FROM %#x\n",ntohl(client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
/*函数向客户端使用write函数发送信息,也可以尝试使用其他函数实现*/
if(-1 == write(nfp,"SOCKET CONNECTED,WELCOME!\n",30));
{
printf("WRITE FAILED\n");
exit(1);
}
printf("WRITE SUCCEED\n");
close(nfp);
}
close(sfp);
return 0;
}
客户端
/*
* Author: xusongqi@live.com
*
* Created Time: 2014年03月20日 星期四 18时42分19秒
*
* FileName: sock_client.c
*
* Description:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#define LENGTH 1024
int main(void)
{
int cfd;//文件描述符
int recbytes;
int sin_size;
char buffer[LENGTH]={0};//接受缓冲区
struct sockaddr_in server_addr,client_addr;//服务器信息,客户端信息
unsigned short portnum=0x8888;//服务端使用的通信端口,可更改,但必须与服务端保持一致
printf("here's a socket client\n");
//建立socket,使用tcp流传输
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1)
{
printf("SOCKET FAILED\n");
exit(1);
}
printf("SOCKET SUCCEED\n");
//构造服务器端的ip及端口信息
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//ip转换为4字节整型,使用时需要根据服务器端ip进行更改
server_addr.sin_port = htons(portnum);//htons将short转化为网络型,即:将小端数据转化为大端数据(以两字节为单位,首尾交换)
//一般来说网络为大端,PPC的cpu为大端,x86的cpu为小端,arm可以配置大小端、
printf("server_addr = %#x, port: %#x\n",server_addr.sin_addr.s_addr,server_addr.sin_port);//打印出小端
//客户端连接服务端,参数顺序为socket描述符,地址信息,地址结构大小
if(-1 == connect(cfd,(struct sockaddr *)(&server_addr),sizeof(server_addr)))
{
printf("CONNECT FAILED\n");
exit(1);
}
printf("CONNECT SUCCEED\n");
//连接成功,从服务器端接收字符
if(-1 == (recbytes = read(cfd,buffer,LENGTH)))
{
printf("READ FAILED\n");
exit(1);
}
printf("READ SUCCEED\n");
buffer[recbytes]='\0';
printf("%s\n",buffer);
//输入任意字符结束程序
puts("press any key to end\n");
getchar();
close(cfd);//关闭连接
return 0;
}
双向自由交互套结字
服务端
/*
* Author: xusongqi@live.com
*
* Created Time: 2014年03月121日 星期三 17时26分23秒
*
* FileName: while_sock_server.c
*
* Description:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <linux/in.h>
#include <string.h>
#include <sys/socket.h>
#define LENGTH 1024
int main(void)
{
//write()相关变量
int sfp,nfp;//两个描述符
struct sockaddr_in server_addr,client_addr;//服务器地址,客户端地址
int sin_size;//???
unsigned short portnum = 8086;//服务器使用端口
char server_msg[LENGTH];
char sock_flush;
//read()相关变量
char buffer[LENGTH];//存储read()收到的信息
int recbytes;// 计数器,计算buffer收到的字节数
printf("Here's a socket server\n");
sfp = socket(AF_INET, SOCK_STREAM,0);
if(sfp == -1)
{
printf("SOCKET FAILED\n");
exit(1);
}
printf("SOCKET SUCCESS\n");
/*设置监听的端口和IP信息*/
bzero(&server_addr, sizeof(struct sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_addr.s_addr=htonl(INADDR_ANY);
server_addr.sin_port=htons(portnum);
/*bind() 端口绑定函数*/
if(-1 == bind(sfp,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr)))
{
printf("BIND FAILED\n");
exit(1);
}
printf("BIND SUCCESS\n");
/*listen 监听端口函数*/
if(-1 == listen(sfp,5))
{
printf("LISTEN FAILED\n");
exit(1);
}
printf("LISTEN SUCCESS\n");
sin_size = sizeof(struct sockaddr_in);
/*服务端accept函数,调用即进入阻塞状态,等待用户连接。
*在没有用户进行连接时,程序停在此处。
*此处accpet的第二个参数用于获取客户端的端口和地址信息。
*/
nfp = accept(sfp,(struct sockaddr *)(&client_addr),&sin_size);
if(nfp == -1)
{
printf("ACCEPT FAILED\n");
exit(1);
}
printf("ACCEPT SUCCESS\nSERVER START GET CONNECT FROM %#x\n",ntohl(client_addr.sin_addr.s_addr),ntohs(client_addr.sin_port));
if(fork() == 0)
{
/*函数向客户端使用write函数发送信息,也可以尝试使用其他函数实现*/
//尝试发送消息
if(-1 == write(nfp,"SOCKET CONNECTED,WELCOME!\n",30))
{
printf("WRITE FAILED\n");
exit(1);
}
printf("WRITE SUCCESS\n");
//write() 发送消息
while(1)
{
gets(server_msg);
if(-1 == write(nfp,server_msg,strlen(server_msg)))
{
printf("WRITE FAILED\n");
exit(1);
}
memset(server_msg,0,strlen(server_msg));
//while(((sock_flush = getchar()) != '\n') && (sock_flush != EOF));//flush cache
printf(" 【SEND SUCCESS】\n");
}
close(nfp);
}
else
{
//read() 接收信息
while(1)
{
if( (recbytes = read(nfp,buffer,LENGTH)) <= 0)
{
break;
}
buffer[recbytes]='\0';
printf("%s\n",buffer);
printf(" 【READ SUCCESS】\n");
}
close(nfp);
}
close(sfp);
return 0;
}
客户端
/*
* Author: xusongqi@live.com
*
* Created Time: 2014年03月21日 星期四 17时27分36秒
*
* FileName: sock_client.c
*
* Description:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#define LENGTH 1024
int main(void)
{
int cfd;//句柄,文件描述符
int recbytes;//计数器,计算接收到的字节数
int sin_size;
char buffer[LENGTH]={0};//存储read()收到的数据
char client_msg[LENGTH];//存储write()发送的数据
struct sockaddr_in server_addr,client_addr;//服务器信息,客户端信息
unsigned short portnum=8086;//服务端使用的通信端口,可更改,但必须与服务端保持一致
printf("here's a socket client\n");
//建立socket,使用tcp流传输
cfd = socket(AF_INET,SOCK_STREAM,0);
if(cfd == -1)
{
printf("SOCKET FAILED\n");
exit(1);
}
printf("SOCKET SUCCESS\n");
//构造服务器端的ip及端口信息
bzero(&server_addr,sizeof(struct sockaddr_in));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");//ip转换为4字节整型,使用时需要根据服务器端ip进行更改
server_addr.sin_port = htons(portnum);//htons将short转化为网络型,即:将小端数据转化为大端数据(以两字节为单位,首尾交换)
//一般来说网络为大端,PPC的cpu为大端,x86的cpu为小端,arm可以配置大小端、
printf("server_addr = %#x, port: %#x\n",server_addr.sin_addr.s_addr,server_addr.sin_port);//打印出小端
//connect连接函数,客户端连接服务端,参数顺序为socket描述符,地址信息,地址结构大小
if(-1 == connect(cfd,(struct sockaddr *)(&server_addr),sizeof(server_addr)))
{
printf("CONNECT FAILED\n");
exit(1);
}
printf("CONNECT SUCCESS\n");
//分裂进程,分别进行读read()和写write()
if(fork() == 0)
{
//while(strcmp(buffer, "end")!=0)
while(1)
{
if((recbytes = read(cfd,buffer,LENGTH)) <= 0)
{
//break;
exit(0);
}
buffer[recbytes]='\0';
printf("%s\n",buffer);
printf(" 【READ SUCCESS】\n");
}
close(cfd);//关闭连接
}
else
{
//write() 发送消息
while(1)
{
gets(client_msg);
if(-1 == write(cfd,client_msg,strlen(client_msg)))
{
printf("WRITE FAILED\n");
exit(1);
}
memset(client_msg,0,strlen(client_msg));
//while(((sock_flush = getchar()) != '\n') && (sock_flush != EOF));//flush cache
printf(" 【SEND SUCCESS】\n");
}
close(cfd);
}
close(cfd);//同步关闭read()与write()
return 0;
}
参考资料
《linux c编程实战》童永清