TCP服务器并发处理多个客户端
多进程&多线程
单线程服务器端不能并发处理,多线程处理并发
TCP特点:面向连接的,可靠的,流式服务
- 三次握手,四次挥手
- connect语句发起连接之后开始进程握手,accept语句,send语句
在close之后进行四次挥手 - 可靠性如何保证:应答确认,超时重传,滑动窗口,乱序重排,去重
- 流式服务,send和receive不对应 (粘包问题)
UDP特点:无连接,不可靠,数据报
UDP服务器客户端的编程流程
netstat状态:接受缓冲区和发送缓冲区,当前字节数,以及使用的进程端口号
TCP服务器端代码:
#include<stdio.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<pthread.h>
int create_socket();
void* thread_fun(void* arg)
{
int c = (int)arg;
while (1)
{
char buff[128] = {
0 };
int n = recv(c, buff, 1, 0);
if (n <= 0)
{
break;
}
printf("recv(%d)=%s\n", c, buff);
send(c, "ok", 2, 0);
}
}
int main()
{
int socketfd = create_socket();
assert(sockfd != -1);
while (1)
{
struct sockaddr_in caddr;//存放客户端地址
int len + sizeof(caddr);
int c = accept(sockfd, (struct sockaddr*)&caddr, &len);
if (c < 0)
{
continue;
}
//启动线程
pthread_t id;
pthread_create(&id, NULL, thread_fun, (void*)c);
}
}
int create_socket()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (-1 == sockfd)
{
return -1;
}
struct sockaddr_in saddr;
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
if (-1 == res)
{
return -1;
}
res = listen(sockfd, 5);
if (-1 == res)
{
return -1;
}
return sockfd;
}
UDP服务器端口代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//数据报服务的套接字
assert(sockfd != -1);
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);//端口,网路字节序列,大端
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
assert(res != -1);
while (1)
{
struct sockaddr_in caddr;
int len = sizeof(caddr);
char buff[128] = {
0 };
int n = recvfrom(sockfd, buff, 127, 0, (struct sockaddr*)&caddr, &len);
printf("rec(%d):%s\n", n, buff);
sendto(sockfd, "ok", 2, 0, (struct sockaddr*)&caddr, sizeof(caddr));
}
}
UDP客户端代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int main()
{
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//数据报服务的套接字
assert(sockfd != -1);
struct sockaddr_in saddr;//代表服务端的地址:ip,port
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(6000);//指定服务器端口
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");//指定服务器ip
while (1)
{
char buff[128] = {
0 };
printf("input:\n");
fgets(buff, 128, stdin);
if (strncmp(buff, "end", 3) == 0)
{
break;
}
sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr*)&saddr, sizeof(saddr));
memset(buff, 0, 128);
int len = sizeof(saddr);
recvfrom(sockfd, buff, 127, 0, (struct socksaddr*)&saddr, &len);
printf("buff=%s\n", buff);
}
close(sockfd);
}