1. TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
2. TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付。
3. TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的 UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)。
4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信 。
5. TCP首部开销20字节;UDP的首部开销小,只有8个字节。
6. TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
我们采用tcp通信方式。
将主机字节顺序转换为网络字节顺序的api,使得数据在网络中传播
#include
uint16_t htons(uint16_t host16bitvalue); //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue); //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue); //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue); //返回主机字节序的值
h代表host,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取。
1.创建套接字;
2.为套接字添加信息(IP和端口号);
3.监听网络连接;
4.监听有客户端接入,接收(建立)一个连接;
5.数据交互阶段;
6.关闭套接字,断开连接。
引用外国人一张图:
服务端:
#include
#include /* See NOTES */
#include
//#include
#include
#include
#include
#include
#include
//chenlichen 多方通信
int main(int argc, char **argv)
{
int s_fd;
int c_fd;
int n_read;
char readBuf[128];
int mark = 0;//标记链接进来的客户端顺序
char msg[128] = {0};
// char *msg = "I get your connect";
struct sockaddr_in s_addr;
struct sockaddr_in c_addr;
if(argc != 3){
printf("param is not good\n");
exit(-1);
}
memset(&s_addr,0,sizeof(struct sockaddr_in));
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1. socket
s_fd = socket(AF_INET, SOCK_STREAM, 0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(argv[2])); //返回网络字节序
inet_aton(argv[1],&s_addr.sin_addr);
//2. bind
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
//3. listen
listen(s_fd,10);
//4. accept 实现自动回复
int clen = sizeof(struct sockaddr_in);
while(1){
c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);
if(c_fd == -1){
perror("accept");
}
mark++;//增加设备
printf("get connect: %s\n",inet_ntoa(c_addr.sin_addr));打印连接的客户端地址
if(fork() == 0){
//创建多个子进程;
if(fork()==0){
while(1){
sprintf(msg,"welcom No.%d client",mark);
memset(msg,0,sizeof(msg));
scanf("%s",msg);
write(c_fd,msg,strlen(msg));
sleep(3);//使其等待 相对于心跳包
}
}
//5. read
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd, readBuf, 128);
if(n_read == -1){
perror("read"); //失败
}else{
printf("\nget: %s\n",readBuf);
}
}
break;
}
}
return 0;
}
客户端:
#include
#include
#include
#include
#include
#include
#include
#include
int main(int argc, char **argv)
{
int c_fd;
int n_read;
char readBuf[128];
char msg[128] = {0};
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
//1. socket
c_fd = socket(AF_INET, SOCK_STREAM, 0);
if(c_fd == -1){
perror("socket");
exit(-1);
}
c_addr.sin_family = AF_INET;
c_addr.sin_port = htons(atoi(argv[2]));
inet_aton(argv[1],&c_addr.sin_addr);
//2.connect
if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){
perror("connect");
exit(-1);
}
//创建子进程取写入读取内容
while(1){
if(fork()==0){
while(1){
memset(msg,0,sizeof(msg));
printf("input: \n");
scanf("%s",msg);
; // 获取字符到msg里面 不发消息阻塞在这里
write(c_fd,msg,strlen(msg));
}
}
while(1){
memset(readBuf,0,sizeof(readBuf));
n_read = read(c_fd,msg,128);
if(n_read == -1){
perror("read");
}
else{
printf("get massage from server%d :%s\n",n_read,msg);
}
}
}
return 0;
}