刚学完socket编程 稍微总结下吧
再写代码之前 应该先对tcp三次握手协议有所了解
引用高人的话 简单介绍下
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SEND状态,等待服务器确认;
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
结合图来看下吧
有了以上基础 先看一个简单TCP通信程序
客户端在终端输入字符,发送至服务器端,在服务器端将小写变成大写然后返回客户端
服务器端
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERV_TCP_PORT 6601
#define EXIT_FAILURE 1
int main()
{
int sockfd,len,s,n,i;
struct sockaddr_in sa,ca;
char buf[512];
sockfd = socket(AF_INET,SOCK_STREAM,0);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERV_TCP_PORT);
n = bind(sockfd, (struct sockaddr *) &sa, sizeof(sa));
if(n == -1){
perror("bind"); exit(EXIT_FAILURE);
}
listen(sockfd,5);
len = sizeof(ca);
s = accept(sockfd, (struct sockaddr *) &ca, (socklen_t *) &len);
printf("Connected\n");
for(;;){
n = recv(s,buf,sizeof(buf),0);
buf[n] = 0;
fputs(buf,stdout);
fflush(stdout);
for(i=0; i<n; i++) buf[i] = toupper(buf[i]);
send(s,buf,n,0);
}
}
客户端
#include<stdio.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERV_HOST_ADDR "127.0.0.1"
#define SERV_TCP_PORT 6601
int main()
{
int sockfd,n;
struct sockaddr_in sa;
char sendline[512],buf[512];
sockfd = socket(AF_INET, SOCK_STREAM, 0);
bzero((char *)&sa, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr=inet_addr(SERV_HOST_ADDR);
sa.sin_port=htons(SERV_TCP_PORT);
connect(sockfd, (struct sockaddr *) &sa, sizeof(sa));
printf("Connected\n");
for(;;){
fgets(sendline, 512, stdin);
n = strlen(sendline);
send(sockfd, sendline,n, 0);
n = recv(sockfd,buf,sizeof(buf),0);
buf[n] = 0;
fputs(buf, stdout); fflush(stdout);
}
}
执行結果
./client.exe
aaa
AAA
bbb
BBB
./serve.exe
AAA
BBB
另外 在linux可以用
# netstat -an | grep 6601
tcp 0 0 0.0.0.0:6601 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:6601 127.0.0.1:34165 ESTABLISHED
tcp 0 0 127.0.0.1:34165 127.0.0.1:6601 ESTABLISHED
来显示连接
===================================================================
上面的程序是 一对一通信的,下面提升下难度
利用fork函数 一个服务器端与多个客户端进行通信(fork用法不再介绍)
同样是 一个输入小写字符 返回大写字符
服务器端
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define SERV_TCP_PORT 6601
#define EXIT_FAILURE 1
int main()
{
int sockfd,len,s,n,i;
struct sockaddr_in sa,ca;
char buf[512];
sockfd = socket(AF_INET,SOCK_STREAM,0);
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = htons(SERV_TCP_PORT);
n = bind(sockfd, (struct sockaddr *) &sa, sizeof(sa));
if(n == -1){
perror("bind"); exit(EXIT_FAILURE);
}
listen(sockfd,5);
while(1){
len = sizeof(ca);
s = accept(sockfd, (struct sockaddr *) &ca, (socklen_t *) &len);
printf("Connected\n");
if(fork()!= 0){
close(s);
continue;
}
close(sockfd);
printf("Connected from %s port %u\n", inet_ntoa(ca.sin_addr),ntohs(ca.sin_port));
for(;;){
n=recv(s,buf,sizeof(buf),0);
if(n == 0){
close(socket);
return 0;
}
buf[n]=0;
fputs(buf,stdout); fflush(stdout);
for(i=0;i<n;i++) buf[i]=toupper(buf[i]);
send(s,buf,n,0);
}
}
}
客户端不需要改变
执行结果
# ./client4_1
Connected
aaaaa
AAAAA
# ./client4_1
Connected
bbbbb
BBBBB
# ./server4_4
Connected
Connected from 127.0.0.1 port 34161
aaaaa
Connected
Connected from 127.0.0.1 port 34162
bbbbb